在线程中休眠(C/POSIX线程)

在线程中休眠(C/POSIX线程),c,multithreading,pthreads,sleep,usleep,C,Multithreading,Pthreads,Sleep,Usleep,我正在开发一个多线程应用程序,它利用了。我使用线程来执行周期性的作业,并为此暂停线程执行。我的问题是如何从主线程取消usleep()计时器,我尝试了pthread\u kill(thread,SIGALRM),但它具有全局效果,导致主应用程序终止(默认情况下)。这是我的伪代码: void threaded_task(void *ptr) { initialize(); while(running) { do_the_work(); usleep(

我正在开发一个多线程应用程序,它利用了。我使用线程来执行周期性的作业,并为此暂停线程执行。我的问题是如何从主线程取消usleep()计时器,我尝试了
pthread\u kill(thread,SIGALRM)
,但它具有全局效果,导致主应用程序终止(默认情况下)。这是我的伪代码:

void threaded_task(void *ptr) {
    initialize();

    while(running) {
        do_the_work();
        usleep(some_interval);
    }

    clean_up();
    release_resources();
}
下面是一个伪函数,用于从主线程停止(并正常关闭)给定线程:

void stop_thread(pthread_t thread) {
    set_running_state(thread, 0); // Actually I use mutex staff
    // TODO: Cancel sleep timer so that I will not wait for nothing.
    // Wait for task to finish possibly running work and clean up 
    pthread_join(thread, NULL);
}

实现我的目标的便捷方式是什么?我必须使用条件变量还是可以使用sleep()变量?

使用带有FIFO或套接字的
select()
来唤醒它。

作为
select
的替代方法,也可以使用pthread条件变量(请参见
pthread_cond_init
pthread_cond_wait
pthread_cond_signal
)、SysV信号量或POSIX信号量。所有这些都比usleep更适合事件处理线程。

看起来您是从参考手册页在Linux上运行的。 您应该能够使用nanosleep并中断子进程的应用程序(SIGRTMIN+x)。nanosleep具有被信号中断的功能,并返回其本应已睡眠的剩余时间。如果您正在使用更长的睡眠时间,您也可以只使用睡眠

上面提到的任何类型的IPC也可以帮助您解决这个问题


编辑:看起来您已经在这样做了,但您应该使用不会对程序产生外部影响的信号。任何睡眠功能都应该被非阻塞信号中断。实时信号应该按应用程序使用。

有多种方法可以做到这一点:

  • 使用self-pipe-trick@Ignacio(Linux提供了方便但不可移植的方法来替换这里的管道)
  • 通过围绕互斥体和条件变量构建的阻塞队列连接线程,等待空队列,唤醒队列中的项目
  • 在启动其他线程之前阻止主线程中的信号,等待信号,唤醒信号-请参阅

我们使用pthread\u cond\u timedwait在条件变量上使用一个带超时的等待


当我们想要关闭时,我们设置一个“shutting down”变量并执行pthread_cond_broadcast

SIGALRM杀死整个应用程序的原因是您可能还没有为它注册信号处理程序。SIGALRM的默认操作是内核终止进程,因此如果
usleep
是以手动方式实现的r如果不使用SIGALRM(例如,使用
nanosleep
或具有超时的轮询函数之一),则
usleep
将不会注册处理程序或以其他方式更改信号的默认配置

void handle_alrm(int sig) {
}

...

int main(void) {
    signal(SIGALRM, handle_alrm);
    ...
虽然您应该研究更复杂的
sigaction
函数,而不是
signal
,因为它允许在不同的平台上进行更多的控制和更一致的行为,但应该足以防止终止您的程序


如果您尝试在使用SIGALRM实现
usleep
sleep
的系统上使用代码,则可能会导致问题,因此您可能希望不要使用这些标准库版本,而使用跨所有平台具有更可预测实现的函数(可能是围绕着nanosleep的薄薄包装,它提供了您想要的界面)。

您也可以带着信号灯睡觉(事实上这是他们真正的目的)

线程中有一个
sema\u wait
,主线程中有一个
sema\u post
。这很简单,很干净,很方便携带。这里有一个链接,指向一篇详细介绍此过程的文章:
也许你需要弄乱信号掩码,或者信号无法从usleep中传出……我不知道。我不知道可以使用sigwait()或sigtimedwait()。我们使用pthread_kill唤醒线程,但我们使用sigwait…而不是usleep休眠线程。这是我发现的唤醒线程的最快方法(根据我的测试,比等待pthread秒快40-50倍。)

我们在创建线程之前执行此操作:

int fSigSet;
sigemptyset(&fSigSet);
sigaddset(&fSigSet, SIGUSR1);
sigaddset(&fSigSet, SIGSEGV);
pthread_sigmask(SIG_BLOCK, &fSigSet, NULL);
创建的每个线程都继承了此掩码。我对掩码有点困惑。你要么告诉系统不要对某些信号执行任何操作,要么告诉系统你正在处理某些信号……我不知道。其他人可以插进来帮助我们。如果我能更好地了解掩码的工作方式,我可能能够我会告诉你,你可以把上面的代码粘贴到你的ThreadProc中。另外,我不确定是否需要SIGSEGV

然后一个线程调用它来自行休眠:

int fSigReceived;
// next line sleeps the thread
sigwait(&fSigSet, &fSigReceived);  // assuming you saved fSigSet from above...
// you get here when the thread is woken up by the signal
// you can check fSigReceived if you care what signal you got.
然后执行此操作以唤醒线程:

thread_kill(pThread, SIGUSR1);

因为我使用usleep()只是为了暂停,所以使用了条件变量(和额外的互斥)对我来说是不可取的。sema_wait和sema_post用于同步目的,虽然我的问题与同步有关,但它不是一个互斥问题。阅读链接的文章?信号量也是用于信号传递的,并不是因为大多数人将其误用为互斥对象,所以它们不能用于真正的目的。不管你是谁如果您继续睡眠,条件本身可能是一个信号量。select是unix惯用的小睡眠(可以用fifo拨动)。根据POSIX,使用
sleep
usleep
SIGALRM
usleep实现是不一致的。这也是我的建议。