【发布时间】:2012-03-20 23:36:27
【问题描述】:
以下是我从我正在从事的一个更大的项目中汇总的概念的简要证明。该项目有一个使用CreateThread 创建的工作线程,用于监视目录的更改。我有一些需要运行的清理代码,比如关闭句柄和释放一些内存。
应用程序不作为后台进程或服务运行。它通过命令行运行并一直运行到用户关闭命令窗口或按下Ctrl-C。
有没有更好的方法来做到这一点?我尝试使用atexit,但是当进程被杀死时显然没有被调用。
请注意,我使用的是 C,而不是 C++,并且没有使用 MFC、AFX 或 Windows API 以外的任何其他 API。基于 cmets,我想这其中的另一部分是如何在多线程环境中正确终止应用程序?可以吗,还是我应该在thread_func 内拨打ExitProcess ?
更新:
我已经更新了下面卢克的评论,以设置一个标志来指示应用程序正在终止。我也改成使用atexit来调用清理函数,而不是直接调用。
#include <stdio.h>
#include <windows.h>
HANDLE thread_handle = INVALID_HANDLE_VALUE;
BOOL time_to_quit = FALSE;
DWORD WINAPI thread_func(LPVOID lpvd)
{
fwprintf(stdout, L"thread running...\n");
while (!time_to_quit)
{
/* do stuff */
Sleep(10);
}
return 0;
}
void cleanup()
{
/* clean up code here that needs to be run at exit */
fwprintf(stdout, L"cleaning up...\n");
CloseHandle(thread_handle);
}
BOOL WINAPI console_handler(DWORD event)
{
time_to_quit = TRUE;
return FALSE;
}
int wmain(int argc, wchar_t* argv[])
{
DWORD thread_id = 0;
thread_handle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)thread_func, NULL, 0, &thread_id);
if (thread_handle != NULL)
{
atexit(cleanup);
fwprintf(stdout, L"thread created...\n");
SetConsoleCtrlHandler((PHANDLER_ROUTINE)console_handler, TRUE);
WaitForSingleObject(thread_handle, INFINITE);
}
return 0;
}
【问题讨论】:
-
如您所见,
atexitis only called whenexitis called or the program returns frommain。SetConsoleCtrlHandler不适合你吗? -
CreateThread 在失败时返回 NULL,而不是 INVALID_HANDLE_VALUE。
-
啊,是的,NULL 谢谢。 @Seth,部分问题是我应该如何退出应用程序。我宁愿不要到处打电话给
cleanup。我已经更新了这个问题并进行了一些澄清。 -
@Casey 看起来你只有一个电话给
cleanup。你在哪里叫它?另外你的switch太大了,你不需要break在return之后,你可以使用fallthrough 来避免在每个你想这样做的人上都必须return FALSE,return TRUE可以在default。其实你真的只需要一个if:if (event == CTRL_C_EVENT) cleanup(); return FALSE; -
这是一种常见的模式。在启动时,您清除一个标志(在应用程序关闭时设置)并创建您的工作线程。然后添加 CTRL 处理程序,该处理程序设置标志以指示应用程序应关闭。在您的工作线程循环中,您偶尔会检查该标志,当它被设置时,您会跳出循环并从线程 proc 返回。然后你的主线程等待所有工作线程退出。