我编写了以下结构来实现简单的单生成器/多消费者同步。我使用了两个整数available_index
和consumed_index
,consumed_index
的访问权限受条件变量cv
的保护。这是代码:
#include <iostream>
#include <mutex>
#include <condition_variable>
#include <vector>
#include <thread>
struct ParserSync {
std::mutex worker_lock;
std::condition_variable cv;
int consumed_index = -1;
int available_index = -1;
bool exit_flag = false;
int consume_index() {
int ret = -1;
// get worker_lock
std::unique_lock<std::mutex> w_lock(worker_lock);
// wait for exit_flag or new available index
cv.wait(w_lock, [this] { return exit_flag || available_index > consumed_index; });
if (available_index > consumed_index) {
consumed_index++;
ret = consumed_index;
}
// Unlock mutex and notify another thread
w_lock.unlock();
cv.notify_one();
return ret;
}
void publish_index() {
available_index++;
std::cout << "before" << std::endl;
cv.notify_one();
std::cout << "after" << std::endl;
}
void set_exit() {
exit_flag = true;
cv.notify_all();
}
};
我使用以下代码测试了我的实现(只是一个显示问题的简单示例):
void producer(ParserSync &ps){
for (int i=0;i<5000;i++){
ps.publish_index();
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
ps.set_exit();
std::cout << "Producer finished!" << std::endl;
}
void consumer(ParserSync &ps){
while (true){
int idx = ps.consume_index();
if (idx == -1)
break;
std::this_thread::sleep_for(std::chrono::milliseconds(4));
}
std::cout << "Consumer finished!" << std::endl;
}
int main() {
ParserSync ps{};
const int num_consumers = 4;
std::vector<std::thread> consumer_threads(num_consumers);
// start consumers
for (int i = 0; i < num_consumers; ++i) {
consumer_threads[i] = std::thread{consumer, std::ref(ps)};
}
// start producer
std::thread producer_thread = std::thread{producer, std::ref(ps)};
for (int i = 0; i < num_consumers; ++i) {
consumer_threads[i].join();
}
producer_thread.join();
std::cout << "Program finished" << std::endl;
return 0;
}
我希望生产者线程产生5000个索引并在之后退出,但不幸的是,在某些随机迭代中被卡住。我使用print语句来查找阻塞并跟踪它到cv.notify_one();
的代码行。这是(缩短的)控制台输出:
...
before
after
before
after
before
有谁知道调用cv.notify_one();
的原因是什么?
我在Windows 10上使用MinGW(x86_64-6.2.0-posix-seh-rt_v5-rev1)。
提前致谢!
修改
使用Visual Studio编译完全相同的代码时,程序按预期工作,并且不会锁定自身。不幸的是,由于其他原因,我需要使用MinGW。