Пример простого многопоточного мьютекса неверен
Я ожидаю получить числа от 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 ответа
Вы должны прочитать и записать переменную общего доступа в замке. Вы читаете его за пределами замка и, таким образом, делаете его неуместным.
Но даже этого недостаточно, поскольку ваша общая переменная является переменной цикла, в которую вы пишете без защиты блокировки. Гораздо лучший пример будет выглядеть так:
#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();
}
Если вы можете, используйте критическую секцию, а не мьютекс, потому что они проще в использовании и эффективнее. Но у них та же семантика, что они защищают только код внутри блокирующего блока.
Примечание: у Джерри есть указатель на некоторые другие проблемы, но я сконцентрировался на проблемах высокоуровневой передачи и сериализации.
Ваш synchronized
не так!
Проблема в том, что вы получаете адрес переменной i
в параметрах функции addQuery
- когда работает первый поток - это не гарантирует, что i
все еще имеет значение 0, потому что в то же время оно могло бы быть изменено на следующее значение в вашем цикле.
Возможно, вам понадобится код из ответа Дэвида Хеффернана.