2015-12-20 138 views
0

我想在我的应用程序中写入暂停/取消暂停所有线程,这是由SIGUSR1(暂停)和SIGUSR2(取消暂停)激活的。我想在所有线程中使用pthread_cond_wait(),并且当收到信号时,在条件上使用pthread_cond_broadcast()我会挂起所有线程,但显然在信号处理程序中使用pthread_cond_broadcast()是不安全的...是否有任何其他解决方案来解决此问题(我必须避免忙等待)?pthread - 暂停/暂停所有线程

+0

的每一个地方,例如我不能暂停线程如果他们正在等待来自其他进程的消息的消息队列,则应该在暂停之前完成此操作。 – qiubit

+1

您的处理循环是如何设置的?如果它是基于'select'的,那么当被任何信号中断时,'select'将返回一个错误,'errno'设置为'EINTR'。此时您可以发送广播。或者你甚至可以用'signalfd'将信号明确地加入到你的处理循环中。 – kaylum

回答

4

您可以使用sigwait用于等待信号的专用线程。当收到信号时,返回等待状态,给定线程可以通知正常代码(不是信号处理程序)内的其他线程。

假设你有暂停功能及恢复线程像这些

int paused; 
pthread_mutex m; 
pthread_cond cond; 

void pause_threads(void) 
{ 
    pthread_mutex_lock(&m); 
    paused = 1; 
    pthread_mutex_unlock(&m);   
} 

void unpause_threads(void) 
{ 
    pthread_mutex_lock(&m); 
    paused = 0; 
    pthread_cond_broadcast(&cond); 
    pthread_mutex_unlock(&m);   
} 

专用线程可以通过这种方式来实现:

// Block signals for wait 
sigset_t usr_set; 

sigemptyset(&usr_set); 
sigaddset(&usr_set, SIGUSR1); 
sigaddset(&usr_set, SIGUSR2); 
pthread_sigmask(SIG_BLOCK, &usr_set, NULL); 

// If other threads will be created from given one, they will share signal handling. 
// Otherwise actions above should be repeated for new threads. 

int sig; 
// Repeatedly wait for signals arriving. 
while(!sigwait(&usr_set, &sig)) { 
    if(sig == SIGUSR1) { 
     pause_threads(); 
    } 
    else { 
     unpause_threads(); 
    } 
} 
+0

这是正确的方向。三个评论。首先,没有必要将信号的配置更改为SIG_IGN,因为sigwait没有_delivering_接收待处理信号。其次,我们知道代码是多线程的,因此必须使用'pthread_sigmask'而不是'sigprocmask'(多线程代码中未定义的行为)。第三,这个答案是不完整的 - 它需要像[@ Martinn的回答](http://stackoverflow.com/a/34386678/132382)这样的东西结婚成为一个完整的解决方案。 – pilcrow

+0

@pilcrow:谢谢你的评论!在我认为应该处理任何捕获的信号之前(当未被阻塞时)。现在我看到'sigwait'是该规则的例外。至于第三条评论,根据问题,OP肯定知道如何处理捕获的信号。但我为了illustrativness的目的添加了一些示例代码。 – Tsyvarev

1

你有没有尝试过这样的事情:

pthread_mutex_lock(&m_suspend_mutex); 
    while (m_suspend_flag == 1) 
    { 
     pthread_cond_wait(&m_resume_cond, &m_suspend_mutex); 
    } 
    pthread_mutex_unlock(&m_suspend_mutex); 

这将暂停线程,直到另一个线程设置m_suspend_flag为0。这可以被放置在一个战略位置,在你的线程执行周期。对于您的场景,您可以在线程检查消息队列中是否有任何消息之后放置这一小段代码。

+0

问题是,我需要挂住所有线程,所以如果我在每个线程上都这样做,则没有线程可以将它们唤醒... – qiubit

+0

什么将恢复您暂停的最后一个线程? – nobism

+0

我想在收到SIGUSR2时取消暂停所有线程,这正是我想解决的问题。另外,我不需要挂起所有的线程,如果有一种方法可以编写一些线程来唤醒所有其他线程,而不需要忙于等待,那也是有效的解决方案。 – qiubit