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