2015-12-20 187 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