zoukankan      html  css  js  c++  java
  • (十一)boost库之多线程间通信

    (十一)boost库之多线程间通信

    1、互斥锁

    编程中,引入了对象互斥锁的概念,来保证共享数据操作的完整性。每个对象都对应于一个可称为" 互斥锁" 的标记,这个标记用来保证在任一时刻,只能有一个线程访问该对象。

    #include <iostream>
    
    #include <boost/thread.hpp>
    
    using namespace std;
    
    
    
    int g_num = 0;
    
    boost::mutex mu;  //定义互斥锁对象
    
    
    
    int Func(int nCount)
    
    {
    
        for (int i = 0; i < nCount; i++)
    
        {
    
            boost::mutex::scoped_lock lock(mu);  //对共享数据进行操作,需加锁
    
            g_num++;
    
            cout << __FUNCTION__ << ": " << g_num << endl;
    
        }
    
        return g_num;
    
    }
    
    
    
    int _tmain(int argc, _TCHAR* argv[])
    
    {
    
        boost::thread th1(Func, 100);
    
        boost::thread th2(Func, 200);
    
        th1.join();
    
        th2.join();
    
        return 0;
    
    }

    2、读写锁

    
    
    boost::shared_mutex rw_mu;   //定义读写锁
    
    int Write(int nCount)
    
    {
    
        for (int i = 0; i < nCount; i++)
    
        {
    
            boost::unique_lock<boost::shared_mutex> lock(rw_mu);   //加唯一锁
    
            g_num++;
    
            cout << __FUNCTION__ << ": " << g_num << endl;
    
        }
    
        return g_num;
    
    }
    
    
    
    void Read(int nCount)
    
    {
    
        for (int i = 0; i < nCount; i++)
    
        {
    
            boost::shared_lock<boost::shared_mutex> lock(rw_mu);  //加共享锁
    
            cout << __FUNCTION__ << ": " << g_num << endl;
    
        }
    
    }
    
    
    
    int _tmain(int argc, _TCHAR* argv[])
    
    {
    
        boost::thread th1(Write, 100);
    
        boost::thread th2(Read, 100);
    
        boost::thread th3(Read, 100);
    
        th1.join();
    
        th2.join();
    
        th3.join();
    
        return 0;
    
    }

    3、条件量

    条件量相对于互斥锁和读写锁来说,并不是那么好理解,简单点说,条件变量就是用于等待某个条件被触发,但为什么要配合锁使用呢,因为我们的等待不能是干等,那样可能会出现死锁。

    如线程A负责添加任务到队列,线程B负责处理队列中的任务,队列就是两个线程的共享资源,使用前必须加锁,但如果B线程加锁后,发现队列中没有数据,然后等待,A线程准备添加任务时,发现

    锁已经被占用,于是就没法添加任务,就形成了死锁。但如果我等待时,释放锁资源,A线程就能正常添加任务,完成后通知B线程可以处理了,那么整个流程就畅通无阻了,这就是条件量的作用。

    
    
    #include <queue>
    
    boost::mutex g_ioMutex;    //输出控制锁
    
    template<typename T>
    
    class CMsgQueue
    
    {
    
    public:
    
        CMsgQueue(size_t n):m_nCapacity(n)
    
        {
    
        }
    
        void Push(const T& val)
    
        {
    
            {
    
                boost::mutex::scoped_lock lock(m_mu);              //加锁
    
                while(m_val.size() == m_nCapacity)                 //队列已满
    
                {
    
                    {
    
                        boost::mutex::scoped_lock lock(g_ioMutex);
    
                        cout << "队列已满" << endl;
    
                    }
    
                    m_condPush.wait(m_mu);                         //等待,将暂时的解锁
    
                }
    
                 m_val.push(val);                                   //添加数据到队列
    
            }
    
            m_condPop.notify_one();                                 //通知读线程
    
        }
    
        void Pop(T& val)
    
        {
    
            {
    
                boost::mutex::scoped_lock lock(m_mu);               //加锁
    
                while(m_val.size() == 0)                            //队列为空
    
                {
    
                    {
    
                        boost::mutex::scoped_lock lock(g_ioMutex);
    
                        cout << "队列为空" << endl;
    
                    }
    
                    m_condPop.wait(m_mu);                           //等待可读,
    
                }
    
                val = m_val.front();                                 //读取数据
    
                m_val.pop();
    
            }
    
            m_condPush.notify_one();                                 //通知写线程
    
        }
    
    
    
    private:
    
        queue<T> m_val;                            //队列
    
        int m_nCapacity;                           //队列最大容量
    
        boost::condition_variable_any m_condPush;  //写入条件量
    
        boost::condition_variable_any m_condPop;   //读取条件量
    
        boost::mutex m_mu;                         //互斥锁
    
    };
    
    
    
    CMsgQueue<int> g_numQueue(10);
    
    void FuncA(int nCount)
    
    {
    
        for (int i = 0; i < nCount; i++)
    
        {
    
            {
    
                boost::mutex::scoped_lock lock(g_ioMutex);
    
                cout << __FUNCTION__ << " Put " << i << endl;
    
            }    
    
            g_numQueue.Push(i);
    
            
    
        }
    
    }
    
    
    
    void FuncB(int nCount)
    
    {
    
        for (int i = 0; i < nCount; i++)
    
        {        
    
            int val;
    
            g_numQueue.Pop(val);
    
            boost::mutex::scoped_lock lock(g_ioMutex);
    
            cout << __FUNCTION__ << " Get " << val << endl;
    
        }
    
    }
    
    
    
    int _tmain(int argc, _TCHAR* argv[])
    
    {
    
        boost::thread th1(FuncA, 50);
    
        boost::thread th2(FuncB, 20);
    
        boost::thread th3(FuncB, 30);
    
        th1.join();
    
        th2.join();
    
        th3.join();
    
        return 0;
    
    }

    在多线程程序中,锁的使用需要特别的小心,比如,我们将FuncA稍微改一下:

    void FuncA(int nCount)
    
    {
    
        for (int i = 0; i < nCount; i++)
    
        {    
    
            boost::mutex::scoped_lock lock(g_ioMutex);
    
            cout << __FUNCTION__ << " Put " << i << endl;        
    
            g_numQueue.Push(i);    
    
        }
    
    }

    如果改成这样,程序将陷入死锁,我们轻轻松松就制造了一个死锁案例。

    A线程占用了输入锁,那么B线程的Pop函数将一直在获取输入锁的地方等待,但它已经占用了m_mu锁,A线程也就只能一直在等待m_mu,故形成了死锁。

  • 相关阅读:
    jQuery easyUI 的combogrid进行模糊匹配
    SQL 快速生成不重复的卡号
    用SQL语句查找包含有某个关键字的存储过程、触发器、函数等等
    C# DateTime日期格式化
    【SQL触发器】类型 FOR 、AFTER、 Instead of
    【BAT】批量给制定类型的文件名添加前缀
    【VBA】将Excel数据转化为txt文本数据
    【Python】将多个工作簿中的数据按列合并到同一个工作表
    【Python】从DB2数据库中取出字段信息并根据字段类型生成SQL
    【Oracle】多行数据合并为一行,使用逗号分隔
  • 原文地址:https://www.cnblogs.com/timssd/p/5544682.html
Copyright © 2011-2022 走看看