c ++ threading:cv.notify_one()阻止?

时间:2017-01-05 20:29:25

标签: c++ multithreading c++14 mingw-w64 condition-variable

我编写了以下结构来实现简单的单生成器/多消费者同步。我使用了两个整数available_indexconsumed_indexconsumed_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。

0 个答案:

没有答案