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

时间:2010-10-25 16:34:40

标签: c multithreading pthreads sleep usleep

我正在开发一个使用POSIX Threads的多线程应用程序。我正在使用线程来执行期刊作业,为此我使用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()变体吗?

8 个答案:

答案 0 :(得分:9)

USe select()使用FIFO或套接字,您可以戳它以唤醒它。

答案 1 :(得分:6)

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

你线程中的sema_wait和主线程中的sema_post。它很简单,干净,便于携带。这是一篇详细介绍该过程的文章的链接: http://www.netrino.com/node/202

答案 2 :(得分:5)

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

void handle_alrm(int sig) {
}

...

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

应足以避免杀死您的程序,但您应该查看更复杂的sigaction函数而不是signal,因为它允许更多控制并在不同平台上更一致地运行。

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

答案 3 :(得分:4)

我们使用pthread_cond_timedwait

在条件变量上使用等待超时

当我们要关机时,我们设置'shuting down'变量并执行pthread_cond_broadcast

答案 4 :(得分:2)

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

答案 5 :(得分:2)

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

nanosleep(2)

signal(7)

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

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

答案 6 :(得分:2)

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

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

答案 7 :(得分:2)

也许你需要弄乱信号掩码,否则信号就无法摆脱睡眠......我不知道。我不知道可以使用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);

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