繁体   English   中英

线程安全数组计数器 C++

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM