我有一个函数myf
将处理器数量的范围作为参数并返回true
。并且true
值的数量应该等于系统可用的处理器总数。但是,当我运行这个程序时,我总是得到的真值数量少于处理器数量。
有人可以帮我解决这个问题吗?
// Header
bool myf(int startIndex, int endIndex)
{
return true;
}
int main(int argc, char** argv)
{
uint data_size = 9260; // Number of data points, here is an arbitrary large number.
int startIndex, endIndex; // Processor index.
int ncpus = sysconf(_SC_NPROCESSORS_ONLN); // Get number of processors.
int PerCPU = data_size / ncpus; // Data points per CPU.
std::thread t[ncpus];
vector<bool> test(ncpus, false); // Variable to collect return values from the myf.
for(int icpu = 0; icpu < ncpus; icpu++)
{
startIndex = icpu * PerCPU;
endIndex = startIndex + PerCPU;
if(((uint) endIndex > data_size)
|| ((icpu == ncpus - 1) && ((uint) endIndex < data_size)))
endIndex = data_size;
// Evaluate function value at each thread.
t[icpu] = std::thread([&] { test[icpu] = myf(startIndex, endIndex); });
}
// Join all threads.
for(int icpu = 0; icpu < ncpus; icpu++)
{
t[icpu].join();
}
// Count output from all the threads.
uint bool_size=0;
for(uint icpu = 0; icpu < test.size(); icpu++)
{
bool_size += test[icpu];
}
// Output should be 64, if ncpus = 64.
cout << " bool_size :: " << bool_size << std::endl;
return 0;
}
g ++ main.cpp -pthread -std = c ++ 0x
答案 0 :(得分:1)
您描述的问题是由于线程的异步执行与主线程循环中索引计数器的增加有关。
for(int icpu = 0; icpu < ncpus; icpu++) {
/* ... */
t[icpu] = std::thread([&] { test[icpu] = myf(startIndex, endIndex); });
}
这里,每个线程都传递一个lambda,它通过引用(包括索引计数器icpu
)捕获它使用的所有对象。因此,线程†的异步执行会导致索引的读取与增量不一致,即,索引可能已经在线程增加了读它。因此,true
的值有时会存储在向量test
中的错误索引处。
此外,这是未定义的行为,因为同时读取和写入同一内存(icpu
)会导致数据竞争。
示例:强>
------ Main thread ------
1. Index is 0 |----------- Thread 1 ------------|
2. Thread 1 is created | |
3. Index is 1 | |---------- Thread 2 -----------
4. Thread 2 is created | Thread 1 reads index 1 here |
5. Index is 2 | | Thread 2 reads index 2 here
6. Thread 3 is created | |
...
解决此问题的一种方法是简单地让lambda捕获icpu
取代值(制作副本)。
t[icpu] = std::thread([&, icpu] { test[icpu] = myf(startIndex, endIndex); });
†请记住,线程执行顺序是由操作系统安排的。