c - Korrekt afslutning af en multi-threaded Windows konsol applikation

Indlæg af Hanne Mølgaard Plasc

Problem



Nedenfor er et kort bevis på konceptet, jeg smed sammen fra et større projekt, jeg arbejder med. Projektet har en arbejdstråd, der oprettes ved hjælp af CreateThread, der overvåger en mappe til ændringer. Jeg har visse oprydningskoder, der skal løbe som lukningshåndtag og frigøre noget hukommelse.


Programmet kører ikke som en baggrundsproces eller tjeneste. Det køres via kommandolinjen og kører, indtil brugeren enten lukker kommandovinduet eller trykker Ctrl-C.


Er der en bedre måde at gøre dette på? Jeg forsøgte at bruge atexit, men det kaldes tilsyneladende ikke, når processen dræbes.


Bemærk at jeg 'bruger C, ikke C ++ og ikke bruger MFC, AFX eller nogen anden API end Windows API. På baggrund af kommentarer tror jeg, at en anden del af dette er, hvordan afslutter jeg ordentligt programmet i et multithreaded miljø? Er det ok, eller skal jeg ringe ExitProcess inden for thread\_func?


UPDATE:
Jeg har opdateret med Luke's kommentar nedenfor for at indstille et flag for at angive, at ansøgningen afsluttes. Jeg har også ændret det for at bruge atexit for at ringe op i oprydning i stedet for at kalde det direkte.


#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...
");
  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...
");
  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...
");
    SetConsoleCtrlHandler((PHANDLER\_ROUTINE)console\_handler, TRUE);
    WaitForSingleObject(thread\_handle, INFINITE);
  }

  return 0;
}

Bedste reference


I en generel forstand kan du muligvis bruge signal ()


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

void my\_sigtrap(int sig)
{
    printf ("
"
        "Signal \%d == \%d received.
"
        "Bye bye
",
        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
");
        signal(SIGINT, SIG\_IGN);
    } else if (orig\_sig\_fun == SIG\_DFL) {
        printf("Signal handled by default.
");
    } else if (orig\_sig\_fun == SIG\_ERR) {
        perror("Failed to set signal
No trap
 --");
    }

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

    return 0;
}