Многопоточная операция записи в массив

У меня есть программа, в которой несколько потоков обновляют значение массива.

#include<windows.h>
#include<iostream>
#include<stdio.h>
HANDLE Mutex;
int n = 100;
static DWORD WINAPI ThreadedUpdate(LPVOID param){
DWORD GetMutex;
GetMutex = WaitForSingleObject(Mutex,INFINITE);
if(GetMutex == WAIT_ABANDONED){
std::cout << "Error : Could not get Mutex for working Thread. " << std::endl;
exit(0);
}
else if(GetMutex == WAIT_OBJECT_0){
int* a = (int*) param;
for(int i = 0 ; i < n ; i++)
a[i] += 100;
}
if(!ReleaseMutex(Mutex)){
std::cout << "Error : Could not relese Mutex." << std::endl;
exit(0);
}
return 0;
}

int main(int argc, char** argv){
int numThreads = 50;
int* a = new int[n];
HANDLE* Th = new HANDLE[numThreads];
Mutex = CreateMutex(NULL,FALSE,NULL);
DWORD t;
for(int i = 0 ; i < n ; i++)
a[i] = 0;
for(int i = 0 ; i < numThreads ; i++)
Th[i] = CreateThread(NULL,0,ThreadedUpdate,(void*)a,0,&t);
WaitForMultipleObjects(numThreads, Th, TRUE, INFINITE);
for(int i = 0 ; i < n ; i++)
std::cout << a[i] << std::endl;
std::getchar();
}

Теперь в вышеуказанной программе я использую мьютекс для синхронизации. Но я заметил, что даже если я не использую синхронизацию, я получаю правильный ответ. Значит ли это, что в этом случае блокировки не нужны? Является ли оператор + = атомарным?
Это всего лишь пример программы. Я использую подобный код в алгоритме машинного обучения, где несколько потоков обновляют вектор. Даже в этом случае я получаю ожидаемый результат без использования блокировки. Использование блокировки делает программу очень медленной, поскольку обновления происходят очень часто.
Я просто хочу убедиться, что если я не использую блокировку, будут ли какие-либо проблемы?

1

Решение

Вам не нужен мьютекс или критическая секция в этом коде, так что пока все пишет а также операции чтения в многопоточной среде выполняются при атомарных операциях.

Атомика в Windows требует long параметры, поэтому начните с изменения вашего массива, чтобы быть long скорее, чем int, Затем измените процедуру потока следующим образом:

static DWORD WINAPI ThreadedUpdate(LPVOID param)
{
for(int i = 0 ; i < n ; i++)
InterlockedAdd((long*)param + i, 100);
return 0;
}

Проверьте это с некоторыми огромными массивами, и я думаю, что это будет делать то, что вы хотите. Ваш main() сводится к:

int main(int argc, char** argv)
{
int numThreads = 50;
long* a = new long[n];
HANDLE* Th = new HANDLE[numThreads];

for(int i = 0 ; i < n ; i++)
a[i] = 0;

for(int i = 0 ; i < numThreads ; i++)
Th[i] = CreateThread(NULL,0,ThreadedUpdate, a, 0, NULL);

WaitForMultipleObjects(numThreads, Th, TRUE, INFINITE);

for(int i = 0 ; i < n ; i++)
std::cout << a[i] << std::endl;
delete [] a;

for (int i=0; i<numThreads; CloseHandle(Th[i++]));
delete [] Th;

std::getchar();
}
0

Другие решения

Других решений пока нет …