Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/url/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 不同线程之间的互斥锁同步_C++_Multithreading_Mutex_Condition Variable_Boost Mutex - Fatal编程技术网

C++ 不同线程之间的互斥锁同步

C++ 不同线程之间的互斥锁同步,c++,multithreading,mutex,condition-variable,boost-mutex,C++,Multithreading,Mutex,Condition Variable,Boost Mutex,由于我最近开始编写多线程程序,这可能是一个愚蠢的问题。我发现了非常棒的互斥和条件变量用法。据我所知,有以下用途: 保护代码/共享资源的部分不被多线程访问损坏。因此,锁定该部分,这样就可以控制访问哪个线程 如果一个线程正在等待另一个线程的资源/条件,那么可以使用cond.wait()而不是每毫秒轮询一次 现在考虑下面的类例子: class Queue { private: std::queue<std::string> m_queue; boost::mutex m_

由于我最近开始编写多线程程序,这可能是一个愚蠢的问题。我发现了非常棒的互斥和条件变量用法。据我所知,有以下用途:

  • 保护代码/共享资源的部分不被多线程访问损坏。因此,锁定该部分,这样就可以控制访问哪个线程
  • 如果一个线程正在等待另一个线程的资源/条件,那么可以使用cond.wait()而不是每毫秒轮询一次
  • 现在考虑下面的类例子:

    class Queue {
    private:
        std::queue<std::string> m_queue; 
        boost::mutex m_mutex; 
        boost::condition_variable m_cond; 
        bool m_exit;
    
    public:
        Queue()
        : m_queue() 
        , m_mutex() 
        , m_cond()
        , m_exit(false) 
        {}
    
        void Enqueue(const std::string& Req) 
        { 
            boost::mutex::scoped_lock lock(m_mutex);
            m_queue.push(Req);
            m_cond.notify_all();
        }
    
        std::string Dequeue() 
        { 
            boost::mutex::scoped_lock lock(m_mutex);
            while(m_queue.empty() && !m_exit) 
            {      
                m_cond.wait(lock);     
            }
    
            if (m_queue.empty() && m_exit) return "";
    
            std::string val = m_queue.front(); 
            m_queue.pop(); 
            return val; 
        }
    
        void Exit()
        {
            boost::mutex::scoped_lock lock(m_mutex);
            m_exit = true;
            m_cond.notify_all();
        }
    } 
    
    类队列{
    私人:
    std::队列m_队列;
    boost::mutex m_mutex;
    boost::条件变量m_cond;
    布尔穆出口;
    公众:
    队列()
    :m_queue()
    ,m_mutex()
    ,m_cond()
    ,m_退出(错误)
    {}
    无效排队(常量std::string&Req)
    { 
    boost::mutex::作用域锁定(m_mutex);
    m_队列推送(Req);
    m_cond.notify_all();
    }
    std::字符串出列()
    { 
    boost::mutex::作用域锁定(m_mutex);
    while(m_queue.empty()&&&!m_exit)
    {      
    m_cond.wait(锁定);
    }
    if(m_queue.empty()&&m_exit)返回“”;
    std::string val=m_queue.front();
    m_queue.pop();
    返回val;
    }
    无效退出()
    {
    boost::mutex::作用域锁定(m_mutex);
    m_exit=true;
    m_cond.notify_all();
    }
    } 
    
    在上面的示例中,可以调用Exit(),它将通知等待出列的线程,该退出了,而不必等待队列中的更多数据。 我的问题是,既然Dequeue已经获得了锁(mumutex),那么如何才能退出获取相同的锁(mumutex)?除非退出队列释放锁,否则只有退出才能获得它吗


    我在析构函数实现中也看到过这种模式,使用相同的类成员互斥体,析构函数通知所有线程(类方法),到了终止它们各自的循环/函数等的时候了。

    正如Jarod在注释中提到的,调用

    m_cond.wait(lock)
    
    保证自动解锁互斥锁,为线程释放互斥锁,并开始侦听条件变量的通知(参见示例)。 这种原子性还确保线程中的任何代码在设置侦听后执行(因此不会错过任何通知调用)。当然,这假设线程首先锁定互斥锁,否则所有赌注都被取消

    另一个需要了解的重要方面是,条件变量可能会受到“”的影响,因此有第二个布尔条件(例如,在这里,您可以检查队列的空性)很重要,这样您就不会被一个空队列唤醒。大概是这样的:

    m_cond.wait(lock, [this]() { return !m_queue.empty() || m_exit; });
    

    正如Jarod在评论中提到的,电话

    m_cond.wait(lock)
    
    保证自动解锁互斥锁,为线程释放互斥锁,并开始侦听条件变量的通知(参见示例)。 这种原子性还确保线程中的任何代码在设置侦听后执行(因此不会错过任何通知调用)。当然,这假设线程首先锁定互斥锁,否则所有赌注都被取消

    另一个需要了解的重要方面是,条件变量可能会受到“”的影响,因此有第二个布尔条件(例如,在这里,您可以检查队列的空性)很重要,这样您就不会被一个空队列唤醒。大概是这样的:

    m_cond.wait(lock, [this]() { return !m_queue.empty() || m_exit; });
    

    m_条件等待(锁定)释放锁。将锁传递给等待呼叫。它将在等待前解锁互斥锁。文档非常清楚,有
    m_cond.wait(lock)释放锁。将锁传递给等待呼叫。它将在等待之前解锁互斥锁。文档非常清楚,谢谢Jarod、super和rubenvb。这很微妙。很高兴知道!我添加了一个很重要的一点(线程需要锁定互斥锁),否则当然没有足够的同步。这一切都很微妙,很容易出错(但一旦你明白了发生了什么,我也很容易纠正)。我建议将它(正如您所做的)包装在一个固定的界面中,这样在“队列”组件完成后您就不必担心这些细节了。谢谢Jarod、super和rubenvb。这很微妙。很高兴知道!我添加了一个很重要的一点(线程需要锁定互斥锁),否则当然没有足够的同步。这一切都很微妙,很容易出错(但一旦你明白了发生了什么,我也很容易纠正)。我建议将它(正如您所做的)包装在一个固定的接口中,这样您就不必在“队列”组件完成后担心这些细节。