在线程访问共享的全局变量时,我无法提出确保互斥的算法。我试图编写一个可以使用全局变量的线程函数,而不是将其切换到局部变量。
到目前为止我有这个代码:
int sumGlobal = 0;
void sumArray(int** array, int size){
for (int i=0; i<size; i++){
for (int j=0; j<size; j++){
sumGlobal += array[i][j];
}
}
}
int main(){
int size = 4000;
int numThreads = 4;
int** a2DArray = new int*[size];
for (int i=0; i<size; i++){
a2DArray[i] = new int[size];
for (int j=0; j<dim; j++){
a2DArray[i][j] = genRandNum(0,100);
}
}
std::vector<std::future<void>> thread_Pool;
for (int i = 0; i < numThreads; ++i) {
thread_Pool.push_back( std::async(launch::async,
sumArray, a2DArray, size));
}
}
我不确定如何保证sumGlobal
不会被每个线程重写。我想正确更新它,以便每个线程在完成后将其值添加到全局变量。我只是想学习线程,而不仅限于非空函数。
答案 0 :(得分:2)
使变量 atomic :
#include <atomic>
...
std::atomic<int> sumGlobal {0};
原子变量免于数据竞争:即使多个线程试图读取和写入它,它也表现良好。通过互斥或无锁的方式实现原子性是由实施完成的。当您使用+=
以原子方式更新变量时,您的示例中不存在不一致的风险。
这个nice video更详细地向您解释了原子是什么,为什么需要它们以及它们是如何工作的。
您也可以按原样保留变量,并使用互斥锁/ lock_gard来保护它,正如@Miles Budnek所解释的那样。问题是,一次只有一个线程可以执行互斥锁保护的代码。在您的示例中,这意味着不同线程中的处理实际上不会真正有效。原子方法应该具有优越的性能:一个线程仍然可以计算索引并读取数组,而另一个线程可以更新全局变量。
答案 1 :(得分:1)
如果您不希望像@Christophe建议的那样使用std::atomic<int>
之类的同步对象,则可以使用std::mutex
和std::lock_guard
手动同步对总和的访问权限。< / p>
int sumGlobal = 0;
std::mutex sumMutex;
void sumArray(...) {
for(...) {
for(...) {
std::lock_guard<std::mutex> lock(sumMutex);
sumGlobal += ...;
}
}
}
请记住,所有锁定和解锁都会产生相当多的开销。