所以我有一个多线程C ++控制台应用程序,我想在其中处理控制台关闭事件以执行清理。
我有一些这样的效果:
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
返回,我的程序会毫不客气地终止,所以我必须等待main()
结束。
然而,在主要结束后,我得到一个例外,告诉我一个互斥体在忙碌时被摧毁,从dynamic atexit destructor for 'mutex'()
抛出。这让我相信一旦main
返回就会破坏静态变量和全局变量,使我的处理函数与无效的全局变量挂钩。
这是标准的指定行为吗?如果是,是否有任何关于如何达到预期效果的想法?
答案 0 :(得分:4)
在这种情况下,我只会泄漏mutex
对象。您不希望在终止最后一个线程之前调用析构函数,并且在最后一个线程终止期间调用它是没有意义的。
std::mutex& mutex = *new mutex; // freed by OS at process exit
答案 1 :(得分:1)
答案 2 :(得分:0)
是的,您的扣除是正确的。似乎最好的选择是取消注册您的处理程序,然后等待它从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
指针本身在线程的整个生命周期内保持有效)。这样一切都会保持活着,直到每个人都完成它。
当然,假设globals
开始时HandlerRoutine
仍然有效。如果情况并非如此(例如,如果系统可以在主要退货之后但在流程结束之前调用处理程序),那么我将删除此答案。
答案 3 :(得分:0)
我很想用互斥体打乒乓球。没有一个,而是两个互斥体。
第一个是mymain
(基本上是main
的副本)。 main
只会致电mymain
。
第二个由HandlerRoutine
保留,并在main
返回后由mymain
获取。
如果你在没有调用HandlerRoutine
的情况下关闭,你就会掉落主要的结尾。
如果您在调用HandlerRoutine
后关闭,则其上的main
阻止完成。
只是计划泄漏mutex
是不够的,就好像在HandlerRoutine
已经计划关闭期间调用main
一样,其server->shutdown
可能无法访问存储器中。
需要做一些关于第二个mutax(HandlerRoutine
访问)的工作来处理竞争条件(在main
已经退出之后被调用 - 或者到达锁定,并且进程正在清理全局变量?)。将HandlerRoutine
互斥锁存储在指针中,并使用无锁技术非常小心地访问它,可能涉及旋转锁。
答案 4 :(得分:0)
为了扩展提及不需要互斥锁的注释,这是一个替代方案:
BOOL WINAPI HandlerRoutine(DWORD)
{
running = false;
server->shutdown();
Sleep(INFINITE);
return TRUE; // just to stop the compiler complaining
}