[英]Thread-safe array counter C++
我有一个包含 1000 多个元素的向量。 我想获取每个元素并使用该元素发出 HTTP 请求,然后在不使用多线程的情况下给我结果。 它会很慢,所以我做了多线程,每次都要检查 100 个元素。
我的问题是,计数器不工作,因为我计划在不检查所有元素的情况下使计数器达到最大值。
这是我的代码片段:
for(int i=0; i<threads; i++){
threadlist.push_back(thread([&]{
while(true){
mutex lock;
lock.lock();
if(counter >= Files::getUsers().size()){
exit(0);
}else {
counter++;
}
lock.unlock();
您在线程内的循环内定义lock
,这意味着每个线程中的每次迭代都将拥有自己的互斥锁,因此您不会获得任何线程同步来保护counter
。 这会给您带来数据竞争,这是未定义的行为。
您需要做的是在for
循环之外定义lock
,就像您对counter
所做的那样,然后捕获互斥量以便所有线程共享它。
或者,您可以将counter
设为std::atomic<whatever_integer_type>
然后您甚至不需要互斥锁,因为counter
会自行同步。
您似乎在每个线程中使用单独的互斥锁。 您需要在每个线程中使用相同的互斥锁才能进行任何同步。
您不能为每个线程使用单独的互斥锁。 您可以在所有线程(或其他一些同步原语)中使用一个互斥量,或者在这种情况下可以使用原子值。
使用互斥锁:
std::vector<std::thread> threadlist;
int counter = 0;
std::mutex m;
int num_threads = 8;
for (int i = 0; i < num_threads; i++) {
threadlist.push_back(thread([&]{
while (true) {
int myValue;
{ // keep critical section minimal to avoid lock contention as much as possible
std::lock_guard<std::mutex> lock(m);
myValue = counter++;
}
if (myValue >= Files::getUsers().size()) {
return;
}
//do calculation with myValue, no other thread will have the same
}
}));
}
与原子
std::vector<std::thread> threadlist;
std::atomic<int> counter {0};
int num_threads = 8;
for (int i = 0; i < num_threads; i++) {
threadlist.push_back(thread([&]{
while (true) {
int myValue = counter.fetch_add(1);
if (myValue >= Files::getUsers().size()) {
return;
}
//do calculation with myValue, no other thread will have the same
}
}));
}
首先将要完成的工作划分为每个线程的单独向量
首先为每个线程准备要完成的工作,这样每个线程都会有自己独立的工作负载:
const int nThreads = NUMBER_OF_THREADS;
const int sizePerThread = Files::getUsers().size() / nThreads;
std::vector<std::thread> threadlist;
// Fills index limits for each thread
std::vector<int> threadLimitIndex;
for (int i=0; i<nThreads; ++i)
threadLimitIndex.push_back(i * sizePerThread);
threadLimitIndex.push_back(Files::getUsers().size());
然后使用每个线程的限制让它们在自己的数据集上工作:
// Does the calculation
for (int i=0; i<nThreads; ++i)
{
threadlist.push_back(thread([&threadLimitIndex]{
for (int myValue=threadLimitIndex[i]; myValue<threadLimitIndex[i+1]; ++myValue)
{
// Do calculation with myValue, no other thread will have the same
}
}
));
}
不需要复杂的控制代码;-)
警告:这是一种分离工作的简单方法,并假设每个值的工作大致相同。 如果每个值要完成的工作差异很大,一些线程会提前完成并停止,而其余线程仍有工作要做,这不是最优的。 为了保证所有线程在所有情况下都工作到结束,你需要实现一个工作队列。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.