Правильное завершение многопоточного консольного приложения Windows - PullRequest
2 голосов
/ 21 марта 2012

Ниже приведено краткое доказательство концепции, которую я собрал из более крупного проекта, над которым я работаю. В проекте есть рабочий поток, созданный с использованием CreateThread, который отслеживает изменения в каталоге. У меня есть определенный код очистки, который должен запускаться как закрытие дескрипторов и освобождение памяти.

Приложение не запускается как фоновый процесс или служба. Он запускается через командную строку и выполняется до тех пор, пока пользователь не закроет командное окно или не нажмет Ctrl-C.

Есть ли лучший способ сделать это? Я попытался использовать atexit, но это, очевидно, не вызывается, когда процесс завершается.

Обратите внимание, что я использую C, а не C ++ и не использую MFC, AFX или любой другой API, кроме Windows API. Основываясь на комментариях, я предполагаю, что другая часть этого - как правильно завершить приложение в многопоточной среде? Это нормально, или я должен позвонить ExitProcess в thread_func?

UPDATE: Я обновил комментарий Люка ниже относительно установки флага, чтобы указать, что приложение завершается. Я также изменил его для использования 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;
}

1 Ответ

0 голосов
/ 21 марта 2012

В общем смысле вы можете использовать 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;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...