WinApi C 多线程:如何等待线程完成?

WinApi C multithreading: how to wait for a thread to finish?

我正在编写一个多线程程序来计算斐波那契、幂和阶乘。而不是使用 Sleep,我想等待线程完成,并且我想按照线程完成的顺序显示线程的 ID(先完成,先显示)。我应该怎么做?

    #include <windows.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <conio.h>

unsigned int n = 0;
int priorytety[3] = { THREAD_PRIORITY_BELOW_NORMAL,THREAD_PRIORITY_NORMAL, THREAD_PRIORITY_ABOVE_NORMAL};
HANDLE watki[3];

DWORD WINAPI Fibbonaci(void *argumenty){
    unsigned long long int prevPrev = 0;
    unsigned long long int prev = 1;
    unsigned long long int wynik = 1;
    while (wynik <= n){
        wynik = prev + prevPrev;
        prevPrev = prev;
        prev = wynik;
    }
    printf("fibbonaci : %llu \n", wynik);
    ExitThread(wynik);
    //return wynik;
}

DWORD WINAPI Potegi(void *argumenty){
    unsigned long long int wynik = 2;
    while (wynik <= n){
        wynik = wynik << 1;
    }
    printf("potegi : %llu \n", wynik);
    return wynik;
}

DWORD WINAPI Silnia(void *argumenty){
    //printf("%d", atoi(argv[argc-1]));
    unsigned long long int wynik = 1;
    unsigned long long int i = 1;
    while (wynik <= n){
        wynik = wynik * i;
        i = i + 1;
    }
    printf("silnia : %llu \n", wynik);
    return wynik;
}


int main(){
    int i;
    DWORD id;
    system("cls");
    scanf_s("%d", &n);
    LPTHREAD_START_ROUTINE WINAPI funkcje[3] = { Fibbonaci, Potegi, Silnia };
    for (i = 0; i < 3; i++)
    {
        watki[i] = CreateThread(
            NULL, // atrybuty bezpieczeństwa
            10000, // inicjalna wielkość stosu
            funkcje[i] , // funkcja wątku
            (void *)n,// dane dla funkcji wątku
            0, // flagi utworzenia
            &id);
        if (watki[i] != INVALID_HANDLE_VALUE)
        {
            //printf("Utworzylem watek o identyfikatorze %x\n", id);
            // ustawienie priorytetu
            SetThreadPriority(watki[i], priorytety[1]);
        }
    }
    Sleep(10000);
    getchar();
}

@WhozCraig 是正确的,您应该使用 WaitForMultipleObjects() to wait for all the threads to finish. Read this SO post 获取更多信息。

但是,这不会告诉您它们结束的顺序,只有当所有这些都完成时。向每个函数添加代码以打印其线程 ID 应该可以做到这一点(使用 GetCurrentThreadId())。例如:

printf("potegi : %llu, thread ID %ld \n", wynik, GetCurrentThreadId());

现在我们不能忘记 printf 语句和线程实际结束之间有时间。你没有在那里做任何工作,但从技术上讲,线程仍然处于活动状态。在多线程环境中,您无法预测 printf 和线程真正终止之间会经过多少时间,无论那里的代码看起来多么少。

如果这种差异对您很重要,那么您需要独立加入每个线程并查看哪个线程先终止。您可以使用零超时在每个线程句柄上重复调用 WaitForSingleObject() 并检测哪个线程先终止。是的,如果在检查第一个线程时第三个线程略早于第二个线程完成,则存在轻微的竞争条件,然后您检查第二个线程并注意到它已终止。你会想念第三个首先完成的事实。这种轮询技术通过在等待时消耗大量 CPU 来改变实验。

就我个人而言,我认为您最好只记录每个线程完成计算其结果的时间(基于系统时钟),而不是其线程终止的时间。使用GetTickCount() or QueryPerformanceCounter()来测量时间。