【问题标题】:Properly terminating a multi-threaded Windows console application正确终止多线程 Windows 控制台应用程序
【发布时间】: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;
}

【问题讨论】:

  • 如您所见,atexit is only called when exit is called or the program returns from mainSetConsoleCtrlHandler 不适合你吗?
  • CreateThread 在失败时返回 NULL,而不是 INVALID_HANDLE_VALUE。
  • 啊,是的,NULL 谢谢。 @Seth,部分问题是我应该如何退出应用程序。我宁愿不要到处打电话给cleanup。我已经更新了这个问题并进行了一些澄清。
  • @Casey 看起来你只有一个电话给cleanup。你在哪里叫它?另外你的switch 太大了,你不需要breakreturn 之后,你可以使用fallthrough 来避免在每个你想这样做的人上都必须return FALSEreturn TRUE 可以在default。其实你真的只需要一个if:if (event == CTRL_C_EVENT) cleanup(); return FALSE;
  • 这是一种常见的模式。在启动时,您清除一个标志(在应用程序关闭时设置)并创建您的工作线程。然后添加 CTRL 处理程序,该处理程序设置标志以指示应用程序应关闭。在您的工作线程循环中,您偶尔会检查该标志,当它被设置时,您会跳出循环并从线程 proc 返回。然后你的主线程等待所有工作线程退出。

标签: c windows winapi


【解决方案1】:

一般来说,你可以使用 signal()

#include <stdio.h>
#include <stdlib.h>    /* exit() */
#include <signal.h>    /* signal() */
#include <unistd.h>    /* sleep() */

void my_sigtrap(int sig)
{
    printf ("\n"
        "Signal %d == %d received.\n"
        "Bye bye\n",
        sig, SIGINT);
    exit(0);
}

int main(void)
{
    void (*orig_sig_fun)(int);

    orig_sig_fun = signal(SIGINT, my_sigtrap);

    if (orig_sig_fun == SIG_IGN) {
        printf("Ignored by default\n");
        signal(SIGINT, SIG_IGN);
    } else if (orig_sig_fun == SIG_DFL) {
        printf("Signal handled by default.\n");
    } else if (orig_sig_fun == SIG_ERR) {
        perror("Failed to set signal\nNo trap\n --");
    }

    setbuf(stdout, NULL); /* Turning off buffering */
    putchar('.');
    while (1) {
        putchar('.');
        sleep(1);
    }

    return 0;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-11
    相关资源
    最近更新 更多