Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/163.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 等待由多个线程通知的条件变量的正确方法_C++_Multithreading_C++11_Concurrency - Fatal编程技术网

C++ 等待由多个线程通知的条件变量的正确方法

C++ 等待由多个线程通知的条件变量的正确方法,c++,multithreading,c++11,concurrency,C++,Multithreading,C++11,Concurrency,我正试图通过C++11并发支持来实现这一点 我有一种工作线程的线程池,所有线程都做同样的事情,其中主线程有一个条件变量数组(每个线程一个,它们需要“启动”同步,即不在循环的前一个周期运行) 然后,该线程必须等待池中每个线程的通知,以再次重新启动其循环。正确的做法是什么?使用一个条件变量并等待某个整数,每个不是主线程的线程都会增加吗?类似(仍在主线程中) unique_lock锁(workers_mtx); workers_完成。等待(锁,[&workers]{return workers=con

我正试图通过C++11并发支持来实现这一点

我有一种工作线程的线程池,所有线程都做同样的事情,其中主线程有一个条件变量数组(每个线程一个,它们需要“启动”同步,即不在循环的前一个周期运行)

然后,该线程必须等待池中每个线程的通知,以再次重新启动其循环。正确的做法是什么?使用一个条件变量并等待某个整数,每个不是主线程的线程都会增加吗?类似(仍在主线程中)

unique_lock锁(workers_mtx);
workers_完成。等待(锁,[&workers]{return workers=cond_arr.size();});

我在这里看到两个选项:

选项1:
join()

基本上,不是使用条件变量来开始线程中的计算,而是为每次迭代生成一个新线程,并使用
join()
等待它完成。然后为下一次迭代生成新线程,以此类推

选项2:锁


只要其中一个线程仍在工作,就不希望主线程发出通知。因此,每个线程都有自己的锁,在进行计算之前锁定,然后解锁。在调用
notify()
之前,您的主线程会锁定它们,然后再解锁它们。

我看不出您的解决方案有什么根本性的错误

workers\u mtx保护
workers
并完成

我们可以用一个计数信号量来抽象它

struct counting_semaphore {
  std::unique_ptr<std::mutex> m=std::make_unique<std::mutex>();
  std::ptrdiff_t count = 0;
  std::unique_ptr<std::condition_variable> cv=std::make_unique<std::condition_variable>();

  counting_semaphore( std::ptrdiff_t c=0 ):count(c) {}
  counting_semaphore(counting_semaphore&&)=default;

  void take(std::size_t n = 1) {
    std::unique_lock<std::mutex> lock(*m);
    cv->wait(lock, [&]{ if (count-std::ptrdiff_t(n) < 0) return false; count-=n; return true; } );
  }
  void give(std::size_t n = 1) {
    {
      std::unique_lock<std::mutex> lock(*m);
      count += n;
      if (count <= 0) return;
    }
    cv->notify_all();
  }
};
或者类似的


.

一个简短的问题斯通:你考虑过吗?对于第一个问题,使用起来并不容易。第二个不起作用,因为当主线程正在等待某个锁时,其他具有不同锁的线程可能会循环多次,这是我不希望看到的!如果在每个周期后工作线程释放锁,然后等待条件变量,并且只有在通知重新锁定并执行一个周期时,才可以。
    unique_lock<std::mutex> lock(workers_mtx);
    workers_finished.wait(lock, [&workers] { return workers = cond_arr.size(); });
struct counting_semaphore {
  std::unique_ptr<std::mutex> m=std::make_unique<std::mutex>();
  std::ptrdiff_t count = 0;
  std::unique_ptr<std::condition_variable> cv=std::make_unique<std::condition_variable>();

  counting_semaphore( std::ptrdiff_t c=0 ):count(c) {}
  counting_semaphore(counting_semaphore&&)=default;

  void take(std::size_t n = 1) {
    std::unique_lock<std::mutex> lock(*m);
    cv->wait(lock, [&]{ if (count-std::ptrdiff_t(n) < 0) return false; count-=n; return true; } );
  }
  void give(std::size_t n = 1) {
    {
      std::unique_lock<std::mutex> lock(*m);
      count += n;
      if (count <= 0) return;
    }
    cv->notify_all();
  }
};
std::vector< counting_semaphore > m_worker_start{count};
counting_semaphore m_worker_done{0}; // not count, zero
std::atomic<bool> m_shutdown = false;

// master controller:
for (each step) {
  for (auto&& starts:m_worker_start)
    starts.give();
  m_worker_done.take(count);
}

// master shutdown:
m_shutdown = true;
// wake up forever:
for (auto&& starts:m_worker_start)
  starts.give(std::size_t(-1)/2);

// worker thread:
while (true) {
  master->m_worker_start[my_id].take();
  if (master->m_shutdown) return;
  // do work
  master->m_worker_done.give();
}