Windows API mutex re-entry issue despite making threads Sleep()

倾然丶 夕夏残阳落幕 提交于 2020-01-07 04:54:05

问题


I'm trying to get my head around Windows API threads and thread control. I briefly worked with threads in Java so I know the basic concepts but something that has worked in Java seems to only work halfway in C++.

What I am trying to do is as follows: 2 threads in one process, sharing a common resource(for this case, the common resource is a pair of two global variables int a, b;).

The first thread should acquire a mutex, use rand() to generate pairs of numbers from 0 to 100 until it gets a pair such that b == 2 * a, then release the mutex.

The second thread should then acquire the mutex, and check if the b == 2 * a condition is true for the given values(printing something like "incorrect" in case it is not), then release the mutex so the first thread can get it back. This process of generating an checking pairs of numbers should be repeated quite a few times, say 500/1000 times.

My code is as follows:

Main:

#define INIT_SEED               time(NULL)
#define NUMBER_OF_CHECKS        250

int a = 0;
int b = 1;

HANDLE mutexHandle = CreateMutex(NULL, FALSE, NULL);

int main()
{
        HANDLE thread1Handle = CreateThread(NULL, NULL, Thread1Behaviour, NULL, NULL, NULL);

        Sleep(50);

        HANDLE thread2Handle = CreateThread(NULL, NULL, Thread2Behaviour, NULL, NULL, NULL);

        WaitForSingleObject(thread1Handle, INFINITE);

        WaitForSingleObject(thread2Handle, INFINITE);

        return 0;
}

Thread 1 behavior:

DWORD WINAPI Thread1Behaviour( LPVOID _ )
{
        srand(INIT_SEED);

        for (int i = 0; i < NUMBER_OF_CHECKS; i++)
        { 
                WaitForSingleObject(mutexHandle, INFINITE);

                do
                {
                        b = rand() % 100;
                        a = rand() % 100;
                } 
                while (b != 2 * a);

                cout << i << ".\t" << b << " " << a << endl;

                ReleaseMutex(mutexHandle);

                Sleep(50);
        }

        return 0;
}

Thread 2 behavior:

DWORD WINAPI Thread2Behaviour( LPVOID _ )
{
        for (int i = 0; i < NUMBER_OF_CHECKS; i++)
        {
                WaitForSingleObject(mutexHandle, INFINITE);

                if (b == 2 * a)
                        cout << i << ".\t" << b << "\t=\t2 * " << a << endl;
                else
                        cout << i << ".\t" << b << "\t=\t2 * " << a << "\tINCORRECT!!!" << endl;

                ReleaseMutex(mutexHandle);

                Sleep(50);
        }

        return 0;
}

The implementation is simple enough(I skipped over the handle validity checks to keep the code short, in case a bad handle could be the cause i can add them in, but I imagine that in case of a bad handle everything should just crash & burn, not work but with incorrect outputs).

I remember for working with threads in Java that i used to sleep for some time to make sure the same thread does not reacquire the mutex. However, when I run the above code, it mainly works as intended however, when the number of checks is big enough, somethimes the first thread gets the mutex 2 times in a row, leading to an output like this:

1.      92 46
2.      66 33
1.      66      =       2 * 33

Which means that at the end, the second thread will end up checking the same pair several times:

249.    80 40
248.    80      =       2 * 40
249.    80      =       2 * 40

I have tried changing the sleep timer value with values between 0 and 250 but this remains the case no matter how large the sleep period is. When I put at least 250 it seems to work about half the time.

Also, if I remove the cout in the first thread, the problem becomes 2-3 times worse, with more botched synchronizations.

And one more thing I noticed is that for a certain configuration of sleep timer and cout/no cout in thread 1, the number of times the mutex is immediately reacquired is the same, so this is completely reproducible(at least for me).

Using logic, I got 2 conflicting conclusions:

  1. Since it MOSTLY works as intended, it might be a synchronization problem, with the way threads "rush" for the mutex as soon as it is available

  2. Since I am able to reproduce this issue in a pretty "deterministic" way, it might mean that it is an issue in the logic of the code

But the above can't both be true at once, so what exactly is the problem here?

EDIT: To clarify the question: I know that mutex is not technically used for order of execution, but in this case, why does it not work as intended and what would be the fix?

Thanks in advance!

来源:https://stackoverflow.com/questions/47253136/windows-api-mutex-re-entry-issue-despite-making-threads-sleep

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!