[英]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.