设定Linux C/C++ 程序的执行时限

本文介绍三种为Linux C/C++程序设定执行时限的方法,包括使用定时器发送终止信号、处理实时信号以及通过线程实现时间监控。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

给Linux C/C++程序设定执行时限

时间管理,是每个现代人的必修课。给一个任务固定的执行时间,是控制整体进度的一种常用方法。
回到程序中: 如何让一个运行时间可能比较长的Linux C/C++程序能够有一个执行时限呢?这就是本文想解答的一个问题。

方法一

最直接的做法就是,起一个timer,设定该timer到期发送 SIGTERM 信号。如果定时器超时后需要做善后工作,那么就给 SIGTERM 信号写一个信号处理函数;若不需要善后工作,则不用写。
代码如下:

// g++ timer.cpp -lrt 

#include <ctime>
#include <cstdlib>
#include <cstdio>
#include <cstring>

#include <signal.h>
#include <unistd.h>

void CreateAndStartTimer(unsigned int wait_seconds)
{
    if (wait_seconds == 0) return; 
    
    timer_t timerid;
    struct sigevent sev;
    struct itimerspec its;
    
    // Create the timer
    sev.sigev_notify = SIGEV_SIGNAL;
    sev.sigev_signo = SIGTERM;
    sev.sigev_value.sival_ptr = &timerid;
    if (timer_create(CLOCK_MONOTONIC, &sev, &timerid) == -1) {
        fprintf(stderr, "Failed to create timer, will continue running.\n");
        return;
    }

    // Start the timer
    its.it_value.tv_sec = wait_seconds;
    its.it_value.tv_nsec = 0;
    its.it_interval.tv_sec = 0;
    its.it_interval.tv_nsec = 0;

    if (timer_settime(timerid, 0, &its, NULL) == -1) {
        fprintf(stderr, "Failed to set timer, will continue running.\n");
    }
}


int main(int argc, char *argv[])
{
    unsigned int wait_seconds = 0;
    
    if (argc != 2) {
        fprintf(stderr, "Usage: %s <time-out-seconds> \n", argv[0]);
        exit(EXIT_FAILURE);
    }
    
    wait_seconds = atoi(argv[1]);
    if (wait_seconds > 0) CreateAndStartTimer(wait_seconds);

    while (1) {
        sleep(1);
    }

    return 0;
}

以上是最简洁的做法。因为要做的工作就是时间到了杀死本进程,因而也没有什么好多做处理的。基本上,本文到此就可以结束了。要注意的主要是,timer_create(), timer_settime(),以及 sigevent 的用法。man一下基本上就比较清楚了。

方法二

不过,在有些情况下,可能需要捕获实时信号;而在设定实时信号的处理函数时,有可能希望暂时屏蔽实时信号,待设置完再进行处理。这些都是比较常见的需求。
这里以另一个程序来演示实时信号以及屏蔽和去屏蔽信号的做法。

// g++ timer.cpp -lrt 

#include <ctime>
#include <cstdlib>
#include <cstdio>
#include <cstring>

#include <signal.h>
#include <unistd.h>

#define errExit(msg)    do { perror(msg); exit(EXIT_FAILURE); } while (0)

#define SIG SIGRTMIN


typedef void (*signal_handler_t) (int, siginfo_t *, void *);

void signal_handler(int signo, siginfo_t * info, void * context)
{
    pid_t myself = getpid();
    kill(myself, SIGTERM);
}


void set_signal_handler(int signo, signal_handler_t handler)
{
    struct sigaction sigaction_info;
    memset(&sigaction_info, 0, sizeof(sigaction_info));
    
    sigset_t sigset_info;
    sigemptyset(&sigset_info);
    
    sigaction_info.sa_handler = NULL;
    sigaction_info.sa_sigaction = handler;
    sigaction_info.sa_mask = sigset_info;
    sigaction_info.sa_flags = SA_SIGINFO;
}

void CreateAndStartTimer(unsigned int wait_seconds)
{
    if (wait_seconds == 0) return; 
    
    timer_t timerid;
    struct sigevent sev;
    struct itimerspec its;
    sigset_t mask;

    set_signal_handler(SIG, signal_handler);
    
    // Block timer signal temporarily
    sigemptyset(&mask);
    sigaddset(&mask, SIG);
    if (sigprocmask(SIG_SETMASK, &mask, NULL) == -1) {
        errExit("sigprocmask");
    }
    
    // Create the timer
    sev.sigev_notify = SIGEV_SIGNAL;
    sev.sigev_signo = SIG;
    sev.sigev_value.sival_ptr = &timerid;
    if (timer_create(CLOCK_REALTIME, &sev, &timerid) == -1) {
        fprintf(stderr, "Failed to create timer, will continue running.\n");
        return;
    }

    // Start the timer
    its.it_value.tv_sec = wait_seconds;
    its.it_value.tv_nsec = 0;
    its.it_interval.tv_sec = 1;
    its.it_interval.tv_nsec = 0;

    if (timer_settime(timerid, 0, &its, NULL) == -1) {
        fprintf(stderr, "Failed to set timer, will continue running.\n");
    }
    
    // Unblock timer signal 
    if (sigprocmask(SIG_UNBLOCK, &mask, NULL) == -1) {
        errExit("sigprocmask");
    }
}

int main(int argc, char *argv[])
{
    unsigned int wait_seconds = 0;
    
    if (argc != 2) {
        fprintf(stderr, "Usage: %s <time-out-seconds> \n", argv[0]);
        exit(EXIT_FAILURE);
    }
    
    wait_seconds = atoi(argv[1]);    
    if (wait_seconds > 0) CreateAndStartTimer(wait_seconds);

    while (1) {
        sleep(10);
    }

    exit(EXIT_SUCCESS);
}

方法三

最后,还有一种土办法,可以不用timer. 那就是,再开一个线程,在其中写一个 while (true) 的循环,循环体中 sleep(1). 每次醒来的时候,检查一下时间过去了多久。如果时间已经超过了设定的时限,那么就获得本进程的pid,并且发送 SIGTERM 信号给本进程。
这个代码就不列在这里了,可以参见: ThreadTimeKiller

(完)

### C++限制程序运行时间的实现方法 为了限制某个程序或代码段的运行时间,可以通过以下两种主要方式实现:一是设置超时机制并通过信号处理中断长时间运行的任务;二是借助外部工具或守护进程监控子进程的执行情况并强制终止超出规定时限的操作。 #### 方法一:使用 POSIX 信号与定时器 在 Linux 平台下,可以利用 `alarm()` 函数配合信号处理器来设定一个最大允许执行时间。一旦超过指定秒数未完成任务,则触发 SIGALRM 信号从而退出当前流程[^1]。 下面展示了一个简单的例子说明如何应用这种方法: ```cpp #include <signal.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> void handler(int sig) { printf("Time's up! Exiting...\n"); exit(EXIT_FAILURE); } int main(void){ struct sigaction sa; // 设置SIGALRM信号的动作 sa.sa_handler = handler; sigemptyset(&sa.sa_mask); sa.sa_flags = SA_RESTART; if(sigaction(SIGALRM, &sa, NULL) == -1){ perror("sigaction"); exit(EXIT_FAILURE); } alarm(5); // 设定报警时间为5秒钟 sleep(7); // 此处模拟耗时较长的工作 puts("Operation completed within allowed time."); return EXIT_SUCCESS; } ``` 在这个实例里,如果主线程休眠超过了预设的五秒期限,那么就会收到由操作系统发送过来的 SIGALRM 通知进而调用事先注册好的回调函数提前结束整个应用程序。 值得注意的是,这种方式仅适用于那些能够响应异步事件的应用场景,并且可能带来一定的不确定性因为具体行为取决于底层系统的调度策略等因素影响[^2]。 #### 方法二:创建独立线程监视工作进度 另一种更加灵活可靠的办法就是开辟额外的一条或多条并发路径专门负责跟踪目标活动的状态变化直至达到预期条件为止。比如我们可以启动一个新的后台作业定期检查原主体部分是否已经达成既定成果或者耗费掉太多资源尚未得出结论便立即采取措施加以干预停止进一步发展下去以免造成不必要的损失浪费等情况发生。 这里提供一种基于标准库 thread 类型构建而成的基础框架作为参考[^3]: ```cpp #include <iostream> #include <thread> #include <atomic> #include <chrono> std::atomic<bool> keepRunning(true); void workerTask(){ try{ for(auto i=0u;i<1'000'000 && keepRunning.load(); ++i){ /* Simulate some heavy computation */ } }catch(...){ std::cerr<<"Unexpected exception caught during execution!"<<std::endl; } } void watchdog(const unsigned int timeoutSecs){ const auto maxDuration = std::chrono::seconds(timeoutSecs); using namespace std::literals::chrono_literals; if(std::this_thread::sleep_for(maxDuration).count()==maxDuration.count()){ keepRunning.store(false); std::cout<<"\nTimeout reached. Terminating operation prematurely..."<<std::endl; } } int main(){ constexpr unsigned short WORKER_TIMEOUT{3}; // Define acceptable runtime limit here. std::jthread worker(workerTask); std::jthread monitor([WORKER_TIMEOUT]{watchdog(WORKER_TIMEOUT);}); worker.join(); std::puts("Main function finished successfully."); return EXIT_SUCCESS; } ``` 在此设计模式当中,我们分别建立了两个不同的职责分工明确的角色——一个是承担实际业务逻辑运算工作的前台角色;另一个则是担当监管者身份存在的幕后辅助力量。它们之间通过共享变量形式传递必要的控制指令信息相互协作共同维护整体架构稳定高效运转的同时也有效规避了单一串行结构可能导致的各种潜在风险隐患等问题存在可能性大大降低了许多方面都得到了显著改善提升效果非常明显值得推广普及开来让更多开发者受益匪浅。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值