Пример простого многопоточного мьютекса неверен - PullRequest
1 голос
/ 20 октября 2011

Я ожидаю получить числа от 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 ]

5 голосов
/ 20 октября 2011

Вы должны прочитать и записать общую переменную внутри замка.Вы читаете его вне блокировки и, таким образом, делаете блокировку неактуальной.

Но даже этого недостаточно, поскольку ваша разделяемая переменная является переменной цикла, в которую вы пишете без защиты блокировки.Гораздо лучший пример будет выглядеть так:

#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();
}

Если вы можете, используйте критическую секцию, а не мьютекс, потому что они проще в использовании и более эффективны.Но у них та же семантика, что они защищают код только внутри блока блокировки.

Примечание: у Джерри есть указатель на некоторые другие проблемы, но я сконцентрировался на проблемах высокого уровня обработки и сериализации.

0 голосов
/ 28 января 2018

Ваш synchronized не так!

Проблема в том, что вы получаете адрес переменной i в параметрах функции addQuery - когда работает первый поток - это не гарантирует, что i по-прежнему имеет значение 0, потому чтотем временем это могло быть изменено на следующее значение в вашем цикле.

Вам может понадобиться код из ответа Дэвида Хеффернана .

...