2

I'm writing a multithreaded program to calculate Fibonacci, Power and Factorial. Instead of using Sleep, I would like to wait for threads to finish, and I'd like to display ids of threads in the order they finish (first finished, first displayed). How should I do this?

    #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();
}
Barett
  • 5,826
  • 6
  • 51
  • 55
Pan Wolodyjowsky
  • 388
  • 6
  • 26
  • 4
    [`WaitForMultipleObjects`](https://msdn.microsoft.com/en-us/library/windows/desktop/ms687025%28v=vs.85%29.aspx) on that handle array would seem a worthy endeavor. – WhozCraig Apr 09 '15 at 20:23
  • 1
    @WeatherVane `main` for console programs is perfectly fine. – deviantfan Apr 09 '15 at 20:25
  • In Windows, I have used two global variables. One instructs the thread to close before its task is complete, the other is set by the thread to inform when it has closed. Possibly naive but it works well. – Weather Vane Apr 09 '15 at 20:39
  • @WeatherVane: somewhat naive, but still valuable. The first variable is essential if you want to allow for graceful early termination of a thread. Just killing the thread can leave dangling resources, inconsistent states, or worse. The second variable certainly works, and is OK if you only care about the execution of useful work and not the existence of the thread. If the thread is running in a dynamically loaded library, for example, you must use join/WaitForSingleObject to guarantee that the thread has completely finished before unloading the library code. – Randall Cook Apr 09 '15 at 21:30
  • If `WaitForMultipleObjects` won't work for you, for example, because you have too many threads, or because you really need the completion order, another option is a thread-safe queue. Just get each thread to post a notification to the queue just before it exits, and read the queue from the main thread. – Harry Johnston Apr 10 '15 at 00:34
  • @SzymonKaczorowski, if you think my answer is valuable, please consider accepting it. – Randall Cook Apr 13 '15 at 20:50

1 Answers1

3

@WhozCraig is correct that you should use WaitForMultipleObjects() to wait for all the threads to finish. Read this SO post for more information.

That, however, will not tell you the order in which they ended, only when all have completed. Adding code to each function to print its thread ID should do that (use GetCurrentThreadId()). For example:

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

Now we must not forget that there is time between the printf statement and when the thread actually finishes. You are not doing any work there, but technically the thread is still active. In a multithreaded environment, you cannot predict how much time will elapse between the printf and when the thread truly terminates, no matter how little code appears to be there.

If this difference is important to you, then you would need to join each thread independently and see which one terminates first. You could repeatedly call WaitForSingleObject() on each thread handle with a zero timeout and detect which one terminates first. Yes, there is a slight race condition if the third thread finishes slightly before the second while you are checking on the first, and then you check the second thread and notice it has terminated. You'll miss the fact that the third finished first. And this polling technique alters the experiment by consuming a lot of CPU while it is waiting.

Personally, I think you are better off just recording the time (based on the system clock) when each thread finished computing its result, not when its thread terminated. Use GetTickCount() or QueryPerformanceCounter() to measure the time.

Community
  • 1
  • 1
Randall Cook
  • 6,728
  • 6
  • 33
  • 68