2013-02-15 105 views
1
#include <thread> 
#include <chrono> 

using namespace std: 

void f() 
{ 
    // Sleeping for a very long while 
    while (SOCKET s = accept(listening_socket, ...)) 
    { 
     // ... 
    } 

} 

int main() 
{ 
    std::thread t(f); 
    DoSomething(); 
    t.???(); /* What to place here to wake/terminate thread f? */ 
} 

在Win32下,我可以使用TerminateThread()殺死一個線程。但我想要的是一個跨平臺的方法來做到這一點。如何正常喚醒或終止睡眠std ::線程?

我應該如何在C++中優雅地做到這一點?

+8

設計多線程應用程序的一個原則是:「永不殺死線程,讓他們自殺。」 – 2013-02-15 01:33:21

+0

爲什麼你想讓它從第一步開始睡很久? – billz 2013-02-15 01:38:12

+1

對'main'有一個引用而不是一個睡眠的條件變量進行定時等待,並且如果條件觸發然後返回。 – ildjarn 2013-02-15 01:39:08

回答

8

我會建議在廣播信號,信號量,條件變量或其他東西上睡覺,而不是進行阻塞睡眠。然後你的應用程序只是設置信號,任何睡覺將醒來,可以退出。這是一個更清潔的解決方案,因爲它使線程體有機會清理它可能正在做的任何事情 - 包括釋放鎖!

響應更新
在這種特定的情況下,調用select一個超時調用accept之前。

+0

我已更新原始帖子中的示例代碼。線程無法等待給定的事件對象,因爲它在系統提供的函數內被阻塞。 – xmllmx 2013-02-15 01:44:46

4

第一個問題來自阻塞模式套接字接受,你應該使用非阻塞套接字模式。

可以在while循環設置標誌,例如:

struct AcceptHandler 
{ 
    AcceptHandler() 
    : is_terminated(false) 
    { 
    } 

    void accept() 
    { 
    while(!is_terminated) 
    { 
     // select 
     // accept 
     cout << " in loop " << endl; 
    } 
    } 

    void terminate() 
    { 
    is_terminated = true; 
    } 

private: 
    std::atomic<bool> is_terminated; 
}; 

int main() 
{ 
    AcceptHandler ah; 
    std::thread t(std::bind(&AcceptHandler::accept, std::ref(ah))); 
    t.join(); /// this is just demo, it blocks here 

    ah.terminate(); 

    return 0; 
} 

我的例子中,你可以使用條件變量(首選方式)中使用的標誌(is_terminated)。

+0

請注意,這裏有'is_terminated'數據競賽。 – GManNickG 2013-02-15 02:13:46

+0

@GManNickG請提供更多詳情?你的意思是加入並終止? – billz 2013-02-15 02:15:52

+0

如果在任何其他線程同時寫入的變量正在讀取(或寫入)它是一個數據競賽。這裏'is_terminated'可以寫入('is_terminated = true'),同時它被讀取('while(!is_terminated)')。它需要'std :: atomic '(或者用互斥體保護,但這太過於誇張)。 – GManNickG 2013-02-15 02:34:05