使用boost :: lock_guard进行简单的共享数据锁定

kfb*_*kfb 14 c++ boost mutex locking

我是Boost库的新手,我正在尝试实现一个在共享队列上运行的简单生产者和消费者线程.我的示例实现如下所示:

#include <iostream>
#include <deque>
#include <boost/thread.hpp>

boost::mutex mutex;
std::deque<std::string> queue;

void producer() 
{
    while (true) {
        boost::lock_guard<boost::mutex> lock(mutex);

        std::cout << "producer() pushing string onto queue" << std::endl;

        queue.push_back(std::string("test"));
    }
}

void consumer()
{
    while (true) {
        boost::lock_guard<boost::mutex> lock(mutex);

        if (!queue.empty()) {
            std::cout << "consumer() popped string " << queue.front() << " from queue" << std::endl;

            queue.pop_front();
        }
    }
}

int main()
{
    boost::thread producer_thread(producer);
    boost::thread consumer_thread(consumer);

    sleep(5);

    producer_thread.detach();
    consumer_thread.detach();

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

这段代码按照我的预期运行,但是当main退出时,我得到了

/usr/include/boost/thread/pthread/mutex.hpp:45:    
    boost::mutex::~mutex(): Assertion `!pthread_mutex_destroy(&m)' failed.
consumer() popped string test from queue
Aborted
Run Code Online (Sandbox Code Playgroud)

(我不确定输出consumer是否与该位置相关,但我已将其保留.)

我在使用Boost时做错了什么?

Ste*_*end 11

有点偏离主题但相关的imo(...等待评论中的火焰).

这里的消费者模型非常贪婪,不断循环和检查队列中的数据.如果您的消费者线程在数据可用时确定性地唤醒,使用线程间信令而不是此锁定循环,那么它将更有效(浪费更少的CPU周期).以这种方式思考:当队列为空时,这实际上是一个紧密的循环,只是因为需要获取锁.不理想?

void consumer()
{
    while (true) {
        boost::lock_guard<boost::mutex> lock(mutex);

        if (!queue.empty()) {
            std::cout << "consumer() popped string " << queue.front() << " from queue" << std::endl;

            queue.pop_front();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我知道你正在学习,但我不建议在"真正的"代码中使用它.虽然学习图书馆,但没关系.值得赞扬的是,这是一个比理解如何使用lock_guard所必需的更复杂的例子,所以你的目标很高!

最终,您很可能构建(或更好的,如果可用,重用)代码,以便在需要工作时向工作者发出信号,然后您将使用lock_guard工作线程内部来调解对共享数据的访问.


Ser*_*kov 8

您为线程(生产者和消费者)提供mutex对象,然后将其分离.他们应该永远奔跑.然后退出程序,mutex对象不再有效.然而你的线程仍然试图使用它,他们不知道它不再有效.如果您使用过NDEBUG定义,那么您将获得一个coredump.

您是否正在尝试编写守护程序应用程序,这是分离线程的原因?

  • 不要立即退出主线程,也不要分离消费者和生产者.在主线程中等待,直到您的消费者和生产者工作.当他们完成加入他们.然后退出主要. (7认同)

dor*_*ron 5

main退出,所有的全局对象被销毁.但是,您的线程会继续运行.因此,您最终会遇到问题,因为线程正在访问已删除的对象.

底线是你必须在退出之前终止线程.唯一能做到这一点的是让主程序等待(通过使用a boost::thread::join)直到线程完成运行.您可能希望提供某种方式来通知线程完成运行以节省等待太长时间.

另一个问题是,即使没有数据,您的消费者线程也会继续运行.您可能希望等待boost::condition_variable直到发出新数据的信号.