等待main()返回?

所以我有一个multithreading的C ++控制台应用程序,我想在其中处理控制台closures事件以执行清理。

我有这样的效果:

bool running = true; ServerSocket* server; std::mutex mutex; BOOL WINAPI HandlerRoutine(DWORD) { running = false; server->shutdown(); std::lock_guard<std::mutex> guard(mutex); return TRUE; } int main() { std::lock_guard<std::mutex> guard(mutex); SetConsoleCtrlHandler(&HandlerRoutine, TRUE); try { ServerSocket server(27015); ::server = &server; while (running) { TCPSocket* client = server.accept(true); } } catch (const ServerSocket::ServerShutdownException&) { return 0; } } 

如果我从HandlerRoutine返回,我的程序会被HandlerRoutine地终止,所以我必须等待main()结束。

然而,在主要结束后,我得到一个exception,告诉我一个互斥体在繁忙时被破坏,从dynamic atexit destructor for 'mutex'()抛出。 这使我相信,一旦main返回,静态variables和全局variables就会被销毁,而我的处理函数就会被无效的全局variables所笼罩。

这是标准指定的行为,如果是这样,关于如何能达到我想要的效果的任何想法?

在这种情况下,我只是泄漏mutex对象。 你不想在最后一个线程终止之前调用析构函数,在最后一个线程终止的时候没有必要调用它。

 std::mutex& mutex = *new mutex; // freed by OS at process exit 

你可以尝试boost :: application 。

这里的例子是wait_for_termination_request.cpp

是的,你的推论是正确的。 似乎最好的选择是注销你的处理程序,然后等待它完成之前从main()返回。 但是,如果不是出于任何原因的选项,你可以做的其他事情是将所有的全局变量包装在一个结构中:

 struct Globals { bool running; serverSocket* server; std::mutex mutex; }; 

有一个单一的,全局的shared_ptr到该结构的一个实例:

 std::shared_ptr<Globals> globals = std::make_shared<Globals>(); 

在处理程序中创建shared_ptr的副本:

 BOOL WINAPI HandlerRoutine(DWORD) { std::shared_ptr<Globals> myGlobals = globals; ... } 

并且只能依赖于处理程序中的myGlobals (不能保证globals指针本身在线程的整个生命周期内都保持有效)。 这样一切都保持活着,直到每个人都完成了。

当然,这假定当HandlerRoutine开始时globals仍然有效。 如果情况并非如此(即如果系统可以在主返回之后但在流程结束之前调用处理程序),那么我将删除这个答案。

我很想和互斥玩乒乓球。 没有一个,而是两个互斥体。

第一个是由mymain (基本上是你的main副本)。 main做什么,只是叫我的mymain

第二个是由HandlerRoutine持有的,从mymain返回后由main获得。

如果你在没有调用HandlerRoutine情况下关闭,你只需HandlerRoutine main的结尾跳下来。

如果在HandlerRoutine被调用之后关闭,则其上的main块将完成。

简单地计划泄漏mutex是不够的,就好像在main已经计划关闭期间调用HandlerRoutine ,它的server->shutdown可能正在访问无效内存。

为了处理竞争条件(被调用 – 或到达锁定 – 在main已经退出之后,该进程正在清除全局变量?),需要完成第二个mutax( HandlerRoutine访问)的一些工作。 将HandlerRoutine互斥量存储在指针中,并使用无锁技术非常小心地访问它,可能涉及自旋锁。

为了扩大提及互斥是不必要的评论,这是一个选择:

 BOOL WINAPI HandlerRoutine(DWORD) { running = false; server->shutdown(); Sleep(INFINITE); return TRUE; // just to stop the compiler complaining }