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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3726570/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 13:33:58  来源:igfitidea点击:

Using boost::lock_guard for simple shared data locking

c++boostlockingmutex

提问by kfb

I am a newcomer to the Boost library, and am trying to implement a simple producer and consumer threads that operate on a shared queue. My example implementation looks like this:

我是 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;
}

This code runs as I expect, but when mainexits, I get

这段代码按我的预期运行,但是当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

(I'm not sure if the output from consumeris relevant in that position, but I've left it in.)

(我不确定来自consumer该位置的输出是否相关,但我已将其保留。)

Am I doing something wrong in my usage of Boost?

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

采纳答案by Steve Townsend

You give your threads (producer & consumer) the mutexobject and then detach them. They are supposed to run forever. Then you exit from your program and the mutexobject is no longer valid. Nevertheless your threads still try to use it, they don't know that it is no longer valid. If you had used the NDEBUG define you would have got a coredump.

你给你的线程(生产者和消费者)mutex对象,然后分离它们。他们应该永远运行。然后退出程序,mutex对象不再有效。尽管如此,您的线程仍然尝试使用它,他们不知道它不再有效。如果您使用了 NDEBUG 定义,您将获得一个核心转储。

Are you trying to write a daemon application and this is the reason for detaching threads?

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

回答by Steve Townsend

A bit off-topic but relevant imo (...waits for flames in comments).

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

The consumer model here is very greedy, looping and checking for data on the queue continually. It will be more efficient (waste less CPU cycles) if you have your consumer threads awakened determistically when data is available, using inter-thread signalling rather than this lock-and-peek loop. Think about it this way: while the queue is empty, this is essentially a tight loop only broken by the need to acquire the lock. Not ideal?

这里的消费者模型非常贪婪,不断循环并检查队列上的数据。如果您在数据可用时使用线程间信号而不是这种锁定和窥视循环来确定性地唤醒消费者线程,那么效率会更高(浪费更少的 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();
        }
    }
}

I understand that you are learning but I would not advise use of this in 'real' code. For learning the library though, it's fine. To your credit, this is a more complex example than necessary to understand how to use the lock_guard, so you are aiming high!

我知道您正在学习,但我不建议在“真实”代码中使用它。不过,对于学习图书馆来说,这很好。值得称赞的是,这是一个比理解如何使用 lock_guard 所需的更复杂的示例,因此您的目标很高!

Eventually you will most likely build (or better if available, reuse) code for a queue that signals workers when they are required to do work, and you will then use the lock_guardinside your worker threads to mediate accesses to shared data.

最终,您很可能会为一个队列构建(或者更好,如果可用,重用)代码,在需要工作人员工作时向他们发出信号,然后您将使用lock_guard内部工作线程来调解对共享数据的访问。

回答by doron

When mainexits, all the global objects are destroyed. Your threads, however, do continue to run. You therefore end up with problems because the threads are accessing a deleted object.

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

Bottom line is that you must terminate the threads before exiting. The only what to do this though is to get the main program to wait (by using a boost::thread::join) until the threads have finished running. You may want to provide some way of signaling the threads to finish running to save from waiting too long.

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

The other issue is that your consumer thread continues to run even when there is not data. You might want to wait on a boost::condition_variableuntil signaled that there is new data.

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