简单的多线程互斥示例不正确

时间:2011-10-20 19:44:41

标签: windows winapi visual-c++ mutex waitformultipleobjects

我希望以随机顺序从0到4获取数字,但相反,我有一些不同步的混乱

我做错了什么?

#include <iostream>
#include <windows.h>
#include <process.h>

using namespace std;

void addQuery(void *v );

HANDLE ghMutex;

int main()
{
    HANDLE hs[5];
    ghMutex = CreateMutex( NULL, FALSE, NULL);         
    for(int i=0; i<5; ++i)
    {
        hs[i] = (HANDLE)_beginthread(addQuery, 0, (void *)&i);
        if (hs[i] == NULL) 
        {
            printf("error\n"); return -1;
        }
    }

    printf("WaitForMultipleObjects return: %d error: %d\n",
         (DWORD)WaitForMultipleObjects(5, hs, TRUE, INFINITE), GetLastError());


    return 0;
}

void addQuery(void *v )
{
    int t = *((int*)v);
    WaitForSingleObject(ghMutex, INFINITE);

    cout << t << endl;

    ReleaseMutex(ghMutex);
    _endthread();
}

2 个答案:

答案 0 :(得分:5)

您必须在锁内读取和写入共享变量。您正在锁定之外阅读它,从而使锁定无关紧要。

但即使这样也不够,因为你的共享变量是一个你正在写的循环变量而没有锁的保护。一个更好的例子就是这样运行:

#include <iostream>
#include <windows.h>
#include <process.h>

using namespace std;

void addQuery(void *v );

HANDLE ghMutex;
int counter = 0;

int main()
{
    HANDLE hs[5];
    ghMutex = CreateMutex( NULL, FALSE, NULL);         
    for(int i=0; i<5; ++i)
    {
        hs[i] = (HANDLE)_beginthread(addQuery, 0, NULL);
        if (hs[i] == NULL) 
        {
            printf("error\n"); return -1;
        }
    }

    printf("WaitForMultipleObjects return: %d error: %d\n",
         (DWORD)WaitForMultipleObjects(5, hs, TRUE, INFINITE), GetLastError());


    return 0;
}

void addQuery(void *v)
{
    WaitForSingleObject(ghMutex, INFINITE);

    cout << counter << endl;
    counter++;

    ReleaseMutex(ghMutex);
    _endthread();
}

如果可以,请使用临界区而不是互斥锁,因为它们使用起来更简单,效率更高。但它们具有相同的语义,因为它们只保护锁定块内的代码。

注意:Jerry指出了其他一些问题,但我专注于高级别的trheading和序列化问题。

答案 1 :(得分:-1)

您的synchronized没错!

问题是你在函数i的参数中得到变量addQuery的地址 - 当第一个线程运行时 - 它不能保证i仍然具有该值0,因为在此期间它可能已被更改为循环中的下一个值。

您可能需要 David Heffernan 的回复代码。