2

I'm trying to run 3 threads in the same time and then detect in main thread which one has finished. I'm using WaitForMultipleObject function but 3rd thread seems to loop for this WFMO function, while it has already finished its job (printed result).

    #include <Windows.h>
    #include <stdio.h>
    #include <conio.h>
    //---------------------------------------------------------------------------
    #pragma argsused
    struct data 
    {
        char name[50];
    } data[3] = { { "[THREAD 0]" }, { "[THREAD 1]" },{ "[THREAD 2]" } };

    DWORD WINAPI th0()
{
    //here are some calculations
    //also added 1s sleep

    //printing result
    return 0;

}
DWORD WINAPI th1()
{
    //here are some other calculations
    //also added 1s sleep

    //printing result

    return 0;
}
DWORD WINAPI th2()
{
    //here are some other simple calculations
    //also added 1s sleep


    //printing result
    return 0;
}


    int priority[3] = { 0,0, 0};
    HANDLE threads[3]; 
    HANDLE functions[3];


    int main(int argc, char **argv)
    {
        int i;
        DWORD id; // thread's id

        printf("Program started...\n");

        functions[0] = th0;
        functions[1] = th1;
        functions[2] = th2; 
        for (i = 0; i < 3; i++)
        {
            threads[i] = CreateThread(
                NULL, // security atributes
                0, // stack size
                (LPTHREAD_START_ROUTINE)functions[i], // threads
                NULL,// input data for threads
                0, // creation's flags
                &id);//thread's id
            if (threads[i] != INVALID_HANDLE_VALUE)
            {
                printf("Created thread %s with ID: %x\n",
                    data[i].name, id);          
                SetThreadPriority(threads[i], priority[i]);
            }
        }
        bool f0=false, f1=false, f2=false;
        while(!f0 || !f1 || !f2)//while there is any unfinished thread
        {
            DWORD wfmo = WaitForMultipleObjects(3, threads, false, INFINITE);

            if (!f0 && WAIT_OBJECT_0==wfmo)
            {
                printf("%s is done!\n", data[0].name);
                f0=true;
                //CloseHandle(threads[0]);
                //threads[0]=NULL;

            }
            if (!f1 && WAIT_OBJECT_0 +1 == wfmo)
            {
                printf("%s is done!\n", data[1].name);
                f1=true;
                //CloseHandle(watki[1]);
                //watki[1]=NULL;

            }
            if (!f2 && WAIT_OBJECT_0 +2 == wfmo)
            {
                printf("%s is done!\n", data[2].name);
                f2=true;
                //CloseHandle(threads[2]);
                //threads[2]=NULL;
            }
            if(wfmo==WAIT_TIMEOUT)
                printf("timeout\n");
            if(wfmo==WAIT_FAILED)
                printf("failed\n");
        }


        //Sleep(20000); //20s
        return 0;
    }

Output:

    Program started... 
    Created thread [THREAD 0] with ID: b00 
    Created thread [THREAD 1] with ID: a64 
    Created thread [THREAD 2] with ID: 7d0 
    [THREAD 2] Result: 131072 
    [THREAD 1] Result: 121393 
    [THREAD 0] Result: 362880 
    [THREAD 2] is done! 
    [THREAD 0] is done!
orzel
  • 122
  • 1
  • 11

2 Answers2

1

From the MSDN WaitForMultipleObjects documentation :

If bWaitAll is FALSE, the return value minus WAIT_OBJECT_0 indicates the lpHandles array index of the object that satisfied the wait. If more than one object became signaled during the call, this is the array index of the signaled object with the smallest index value of all the signaled objects.

Once the thread 0 is finished, the return value will always be WAIT_OBJECT_0.

ElderBug
  • 5,926
  • 16
  • 25
  • Thanks mate! Now I just need to figure out how to catch data which I want. – orzel Mar 30 '15 at 14:03
  • @orzel Note that calling `WaitForMultipleObjects` with `false` is pointless if one handle is already signaled. It will just always return immediately, which defeats the purpose of waiting. – ElderBug Mar 30 '15 at 14:09
  • I already soved my problem using your tip. Changed my while loop for bunch of ifs, will post it below. – orzel Mar 30 '15 at 14:17
0

Solution (instead of while loop):

DWORD wfmo = WaitForMultipleObjects(3, threads, false, INFINITE);
//HANDLE threads2[2];   
if ( WAIT_OBJECT_0==wfmo)//move th1 and th2 up 
{
    printf("%s is done!\n", data[0].name);
    threads[0]=threads[1];
    threads[1]=threads[2];
    data[0]=data[1];
    data[1]=data[2];
    threads[2]=NULL;

}
else if ( WAIT_OBJECT_0 +1 == wfmo) //move th2 up
{
    printf("%s is done!\n", data[1].name);      
    threads[1]=threads[2];
    data[1]=data[2];
    threads[2]=NULL;
}
else if (  WAIT_OBJECT_0 +2 == wfmo)//no need to do anything
{
    printf("%s is done!\n", data[2].name);
    threads[2]=NULL;
}

wfmo = WaitForMultipleObjects(2, threads, false, INFINITE); 
if ( WAIT_OBJECT_0==wfmo)       
{
    printf("%s is done!\n", data[0].name);
    threads[0]=threads[1];
    data[0]=data[1];
    threads[1]=NULL;
}
else if ( WAIT_OBJECT_0 +1 == wfmo)     
{
    printf("%s is done!\n", data[1].name);

    threads[1]=NULL;
}

wfmo = WaitForMultipleObjects(1, threads, false, INFINITE);
if ( WAIT_OBJECT_0==wfmo)   
    printf("%s is done!\n", data[0].name);
orzel
  • 122
  • 1
  • 11
  • In the first `if` block, I think you could just copy the `[2]` elements to `[0]` rather than shuffling `[1]` to `[0]` and `[2]` to `[1]`. – TripeHound Mar 30 '15 at 14:58
  • You could write this as a loop to save a lot of typing. (Imagine if you had to wait for 10 threads.) Remove the handle that got signaled from the table, reduce the number of handles, and loop back if the number of handles is nonzero. – Raymond Chen Mar 30 '15 at 15:02