2013-02-15 73 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