(十一)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,故形成了死锁。

(十一)boost库之多线程间通信的更多相关文章

  1. (十二)boost库之多线程高级特性

    (十二)boost库之多线程高级特性 很多时候,线程不仅仅是执行一些耗时操作,可能我们还需要得到线程的返回值,一般的处理方法就是定义一个全局状态变量,不断轮训状态,就如我目前维护的一个项目,全局变量定 ...

  2. (十)boost库之多线程

    (十)boost库之多线程 1.创建线程 使用boost库可以方便的创建一个线程,并提供最多支持9个参数的线程函数,相对于void*来说,方便了很多,创建线程主要提供了一下3种方式: 线程库头文件:# ...

  3. Java 多线程间通信

    JDK 1.5 以后, 将同步和锁封装成了对象, 并将操作锁的隐式方法定义到了该对象中, 将隐式动作变成了显示动作. Lock 接口 Lock 接口, 位于 java.util.concurrent. ...

  4. Java多线程间通信-解决安全问题、等待唤醒机制

    /*1.增加一个知识点一个类怎么在所有的类中,让其它类来共同修改它的数据呢?可以用单例设计模式可以用静态可以在其它类中做一个构造函数,接受同一个对象,这样就可以实现对象 2.状态选择可以用数字0 1 ...

  5. 多线程间通信之AutoResetEvent和ManualResetEvent的原理分析和开发示例

    AutoResetEvent 允许线程通过发信号互相通信. 通常,当线程需要独占访问资源时使用该类. 线程通过调用 AutoResetEvent 上的 WaitOne 来等待信号. 如果 AutoRe ...

  6. java 多线程间通信(二)

    传统的线程通信 Object提供了三个方法wait(), notify(), notifyAll()在线程之间进行通信,以此来解决线程间执行顺序等问题. wait():释放当前线程的同步监视控制器,并 ...

  7. 多线程间通信之AutoResetEvent和ManualResetEvent的原理分析

    AutoResetEvent 允许线程通过发信号互相通信. 通常,当线程需要独占访问资源时使用该类. 线程通过调用 AutoResetEvent 上的 WaitOne 来等待信号. 如果 AutoRe ...

  8. java 多线程间通信(一)

    synchronized同步 package com.test7; public class Run { public class MyObject { private int a; public M ...

  9. boost库:多线程

    1.线程管理 最重要的一个类是boost::thread,是在boost/thread.hpp里定义的,用来创建一个新线程. #include <boost/thread.hpp> #in ...

随机推荐

  1. android继续学习相关

    最近不是很忙,但是慢慢就忘记了学习. 我总是选中了一条路后,怀疑它的正确性.我也知道这不好. 一年前,我买了一个ipad,然后玩app上的游戏,觉得很好玩,而且上面很多都是收费的, 当时就觉得,为什么 ...

  2. Silverlight 结合ArcGis 在地图画面上显示名称+ 点选图层事件委派

    原文 http://www.dotblogs.com.tw/justforgood/archive/2012/05/10/72083.aspx 如下图,我希望我的滑鼠经过此标记的点时显示名称 其实简单 ...

  3. ubuntu下集群设置静态ip

    hadoop集群时,需要固定集群内计算机相互通信之间的ip地址,但是每次进行网络连接后,ip地址都是变换的,我们希望设置一个用于集群内通信的静态ip,即使重启电脑也不会变化,同样希望能够正常的访问互联 ...

  4. shell脚本书写总结

    1.shell脚本,如果重定向到文件中,则在脚本中不可以sed -i,如果用了sed -i ,则自打用了sed -i之后的打印都不能再重定向到输出文件了. 2.shell脚本中,如果将命令写在字符串里 ...

  5. Android Studio代码自己主动提示无效(not available in Power Save mode)

    针对一位博友提的问题,我这边写出来,预计还是非常多人会碰到这个问题,可是不知道怎样解决的. 就是在设置了代码自己主动提示功能后,发现不生效的,怎样设置代码自己主动提示请戳这:Android Studi ...

  6. Ruby中,&:(ampersand colon)的用法

    前几日看Ruby代码,发现一个奇怪的用法,如下: a=['a', 'b', 'c'].map! &:upcase p a #["A", "B", &qu ...

  7. iOS UIScrollView的简单使用

    本文代码下载 http://vdisk.weibo.com/s/BDn59yfnBVMAJ // // ViewController.m // ScrollView_T1119 // // Creat ...

  8. Android服务之AIDL

    在android开发过程中,为了让其他的应用程序,也可以访问本应用程序的服务,android系统采用远程过程调用来实现.android通过接口来公开定义的服务.我们将能够夸进程访问的服务成为AIDL服 ...

  9. Docker 生成Node.js web app(含端口映射)

    1.新建目录src,并进入src目录 [xiejdm@localhost Documents]$ mkdir src [xiejdm@localhost Documents]$ cd src/ 2.创 ...

  10. java字符串数组进行大小排序

    若是将两个字符串直接比较大小,会包:The operator > is undefined for the argument type(s) java.lang.String, java.lan ...