睡在线程中(C / POSIX线程)

我正在开发一个使用POSIX线程的multithreading应用程序。 我正在使用线程来做一个定期的工作,为此我正在使用usleep(3)来暂停线程执行。 我的问题是如何从主线程取消usleep()计时器,我尝试了pthread_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() ,你可以戳它以唤醒它。

你也可以用信号量睡觉(这实际上是他们的真正目的)。

你的线程中的sema_post和主线程中的sema_post 。 它很简单,干净,便携。 这是指向详细说明该过程的文章的链接: http : //www.netrino.com/node/202

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

 void handle_alrm(int sig) { } ... int main(void) { signal(SIGALRM, handle_alrm); ... 

尽管你应该考虑更复杂的sigaction函数而不是signal ,因此它应该足以避免杀死你的程序,因为它允许更多控制并且在不同平台上表现得更加一致。

如果您尝试在使用SIGALRM实现usleepsleep的系统上使用代码,这可能会导致问题,因此您可能希望不使用这些代码的标准库版本并使用具有更可预测的实现的函数所有平台(可能是nanosleep周围的薄包装,提供您想要的接口)。

我们使用pthread_cond_timedwait对条件变量进行等待,并使用超时

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

作为select的替代方法,还可以使用pthread条件变量(请参阅pthread_cond_initpthread_cond_waitpthread_cond_signal ),SysV信号量或POSIX信号量。 对于事件处理线程而言,所有这些都比使用睡眠更好。

看起来您正在从引用的手册页上运行Linux。 您应该能够使用nanosleep和interupt与确定的应用程序(SIGRTMIN + x)到子进程。 Nanosleep具有被信号中断的function,并返回它应该睡觉的剩余时间。 如果你使用更长的时间睡觉,你也可以使用睡眠。

了nanosleep(2)

信号(7)

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

编辑:看起来你已经在做这个了,除非你应该使用一个不会对程序产生外部影响的信号。 任何睡眠function都应该被非阻塞信号中断。 实时信号旨在基于每个应用程序使用。

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

  • 使用自管道技巧@Ignacio提及(Linux提供方便,但不便携, eventfd(2)来替换管道)
  • 通过围绕互斥锁和条件变量构建的阻塞队列连接线程,等待空队列,唤醒队列中的项目
  • 在启动其他线程之前阻塞主线程中的信号,等待信号,唤醒信号 – 请参阅pthread_sigmask(3)

也许你需要弄乱信号掩码,否则信号就无法摆脱睡眠……我不知道。 我不知道可以使用sigwait()或sigtimedwait()。 我们使用pthread_kill来唤醒线程,但是我们使用sigwait来睡觉它们….不是我们睡觉。 这是我发现唤醒的最快方法(根据我的测试,比等待pthread_cond快40-50倍。)

我们在创建线程之前这样做:

 int fSigSet; sigemptyset(&fSigSet); sigaddset(&fSigSet, SIGUSR1); sigaddset(&fSigSet, SIGSEGV); pthread_sigmask(SIG_BLOCK, &fSigSet, NULL); 

创建的每个线程都inheritance此掩码。 我对面具有点困惑。 您要么告诉系统不对某些信号做任何事情,要么就是告诉系统您正在处理某些信号……我不知道。 别人可以帮我们出去帮忙。 如果我更好地了解面具的工作方式,我或许可以告诉你,你可以将上面的代码粘贴在你的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);