用C++ 封装linux下的互斥锁MutexLock和条件变量Condition

/*封装互斥锁的时候,要用到的方法,20200605*/
//问题一:MutexLock和Condition是否要设计成单例模式?
//     单例模式只能通过该类创建出一个对象,这意味着只能创建一把锁,如果再来一把锁的话,
//      这显然不符合需求,锁可以有多把,条件变量也可以有多个

//问题二:MutexLock和Condition的成员是否要设计成static?
//      不能设计成static,否则只能是唯一的

//问题三:MutexLock与Condition应该是什么关系?
//       从互斥锁和条件变量的创建以及销毁来看,彼此并不负责对方的生命周期,互不相干,彼此独立
//          由于Condition的接口wait方法是无参的,但是接下来的操作中需要用到互斥锁,MuteLock只能以指针的形式出现在Condition的数据成员中,表达的是一种关联关系(A has B)


//问题四:成员变量引用,需要注意构造函数初始化列表中进行


// MutexLock 和Condition不能进行复制。

class MutexLock
{//先定义接口,再定义实现
public:
    MutexLock();    //构造函数初始化互斥锁
    ~MutexLock();    //析构函数进行销毁互斥锁 pthread_mutex_destroy(pthread——mutex_t*);
    void lock();     //phtread_mutex_lock
    void unlock();  //pthread_mutex_unlock

    pthread_mutex_t *getMutexLockPtr()
    {  return &_mutex2; }   //返回一个   操作锁
       

private:    
        //成员放什么
      //static  pthread_mutex_t  _mutex;          
        pthread_mutex_t _mutex2;
};




class Condition
{
   public:
      //...
            Condition();    //  初始化pthread_cond_init(phtread_cond_t*,);
            ~Condition();    // 销毁  pthread_cond_destroy(pthread_cond_t*);
			void wait();    //   pthread_cond_wait
             //void wait(MutexLock &mutex);//传参的叫依赖关系--->不调用该函数,彼此是无关的
			void notify();    //  pthread_cond_signal
			void notifyall();    //  pthread_cond_broadcast
	 private:
	    //...
        //pthred_mutex_t * _mutex;//不能,要使用已经封装好的MutexLock
        //pthread_mutex_t _mutex;//不能,意味着条件变量的对象要负责互斥锁的销毁
        //MutexLock _mutex;//不能以对象成员的形式出现
        
        MutexLock & _mutex;//可以,用引用(指针)都可以的
        //MutexLock * _mutex;//关联关系(A has  B,彼此并不负责对方生命周期)
        pthread_cond_t _cond;
};
怎么去设计一个合理的类?面向对象设计 OOD,而不是面向过程
最难的是面向对象设计OOD,学习C++的语法知识是在做OOP
OOD难在对于一个需求或问题进行抽象,分析,为了应对需求的变化。


int  pthread_cond_destroy(pthread_cond_t *cond);

分为上半部和下半部
使用条件变量的时候一定要调用互斥锁,因为哟啊操作临界资源

上半部:当加锁之后,调用该方法时,表示当前线程A要进入阻塞状态,但是在进入阻塞状态之前会解锁


下半部:当另外一个线程B调用pthread_cond_signal方法,激活线程A的条件变量,线程A要再往下执行,必须哟啊执行加锁操作,才能往后走,接下来哟啊操作临界资源。
int pthread_cond_wait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex); //内核完成

 

 

代码如下:

MutexLock.hpp   Condition.hpp Condition.cc Test.cc Test2.cc Test3.cc

 

MutexLock.hpp

#ifndef __WD_MUTEXLOCK_H__
#define __WD_MUTEXLOCK_H__

#include <pthread.h>
#include <iostream>
using std::cout;
using std::endl;

namespace wd
{

class MutexLock
{
public:
    MutexLock()
    : _isLocking(false)
    {
        if(0!=pthread_mutex_init(&_mutex,NULL))
        {
            perror("pthread_mutex_init");
        }
    }
    
    //禁止复制控制
    MutexLock(const MutexLock &)=delete;
    MutexLock & operator=(const MutexLock &)=delete;

    ~MutexLock() 
    {
        if(0!=pthread_mutex_destroy(&_mutex))
        {
            perror("pthread_mutex_destroy");
        }
    }

    void lock()
    {
        if(0!=pthread_mutex_lock(&_mutex))
        {
            perror("pthread_mutex_lock");
            return ;
        }
        _isLocking=true;
    }

    void unlock()
    {
        if(0!=pthread_mutex_unlock(&_mutex))
        {
            perror("pthread_mutex_unlock");
            return ;
        }
        _isLocking=false;
    }

    pthread_mutex_t *getMutexLockPtr()
    {//??????
        return &_mutex;
    }
    
    bool isLocking() const 
    {
        return _isLocking;
    }

private:
    pthread_mutex_t _mutex;
    bool _isLocking;
};

class MutexLockGuard
{
public:
    explicit
    MutexLockGuard(MutexLock &mutex)
    : _mutex(mutex)//构造函数加锁
    {
        _mutex.lock();
    }

    ~MutexLockGuard()//析构函数来解锁
    {
        _mutex.unlock();
    }

private://获取一个互斥锁的对象
    MutexLock &_mutex;
};

}//end of namespace wd

#endif

 

 

Condition.hpp

#ifndef __WD_CONDITION_H__
#define __WD_CONDITION_H__
#include "MutexLock.hpp"
#include <pthread.h>
#include <iostream>

using std::cout;
using std::endl;

namespace  wd
{


class Condition
{
public:
    explicit
    Condition(MutexLock & mutex);
    ~Condition(); 
    
    //禁止复制?
    Condition(const Condition &)=delete;
    Condition &operator=(const Condition &)=delete;

    void wait();
    void notify();
    void notifyAll();

private:
    pthread_cond_t _cond;
    MutexLock & _mutex;
};


}
#endif

 

 

Condition.cc


#include "Condition.hpp"
#include <iostream>

using std::cout;
using std::endl;

namespace wd
{
Condition::Condition(MutexLock & mutex)
: _mutex(mutex)
{
    if(0!=pthread_cond_init(&_cond,NULL))
    {
        perror("pthread_cond_init");
    }
}

Condition:: ~Condition()
{
    if(0!=pthread_cond_destroy(&_cond))
    {
        perror("pthread_cond_destroy");
    }
}

void Condition::wait()
{
    if(0!=pthread_cond_wait(&_cond,_mutex.getMutexLockPtr()))
    {
        perror("pthread_cond_wait");
    }
}
void Condition::notify()
{
    if(0!=pthread_cond_signal(&_cond))
    {
        perror("pthread_cond_signal");
    }
}

void Condition::notifyAll()
{
    if(0!=pthread_cond_broadcast(&_cond))
    {
        perror("pthread_cond_broadcast");
    }
}

}//end of namespace wd

 

 

Test1.cc

两个线程抢占式卖票

/*  autor:liulei  */
/*  C++           */
#include "Condition.hpp"
#include <iostream>

using std::cout;
using std::endl;

struct CriticalResource
{
    //构造函数完成对象的初始化
    CriticalResource(long tickets)
    : _tickets(tickets)
    , _mutex()
    , _cond(_mutex)
    {}

    long _tickets=1000;
    wd::MutexLock _mutex;
    wd::Condition _cond;
};

/*1号窗口和2号窗口抢占式的方式卖票*/

void *windowsSale1(void *arg)
{
    cout<<">> windows1: "<<pthread_self()<<endl;
    CriticalResource *presource=static_cast<CriticalResource*>(arg);
    
    while(1)
    {
        presource->_mutex.lock();
        if(presource->_tickets>0)
        {
            presource->_tickets--;
            cout<<"windows1 left:tickets "<<presource->_tickets<<endl;
        }else{
            cout<<"Windows1:tickets has sold out!"<<endl;
            presource->_mutex.unlock();
            break;//票卖完的时候,需要退出线程
        }

        presource->_mutex.unlock();
    }
    return nullptr;
}

void *windowsSale2(void *arg)
{
    cout<<">> windows2: "<<pthread_self()<<endl;
    CriticalResource *presource=static_cast<CriticalResource*>(arg);
    
    while(1)
    {
        presource->_mutex.lock();
        if(presource->_tickets>0)
        {
            presource->_tickets--;
            cout<<"windows2 left:tickets "<<presource->_tickets<<endl;
        }else{
            cout<<"Windows2:tickets has sold out!"<<endl;
            presource->_mutex.unlock();
            break;//票卖完的时候,需要退出线程
        }

        presource->_mutex.unlock();
    }
    return nullptr;
}

void test()
{
    CriticalResource resoure(100000);
    pthread_t pthid1,pthid2;
    pthread_create(&pthid1,nullptr,windowsSale1,(void*)&resoure);
    pthread_create(&pthid2,nullptr,windowsSale2,(void*)&resoure);
    
    cout<<"> main thread:"<<pthread_self()<<endl;

    pthread_join(pthid1,nullptr);
    pthread_join(pthid2,NULL);
}

int main()
{   
    test();
    return 0;
}

 

Test2.cc

两个线程交替卖票

/*  autor:liulei  */
/*  C++           */
#include "Condition.hpp"
#include <iostream>

using std::cout;
using std::endl;

struct CriticalResource
{
    CriticalResource()=default;

    //构造函数完成对象的初始化
    CriticalResource(long tickets)
    : _tickets(tickets)
    , _mutex()
    , _cond(_mutex)
    {}

    long _tickets=1000;
    bool _flag=false;
    wd::MutexLock _mutex;
    wd::Condition _cond{_mutex};
};

/*1号窗口和2号窗口交替卖票*/
//1号卖完了通知2号卖,2号卖完了通知1号卖
//  _flag=true,一号卖,否则一号等待
// _flag=flase,二号卖,否则二号等待
void *windowsSale1(void *arg)
{
    cout<<">> windows1: "<<pthread_self()<<endl;
    CriticalResource *presource=static_cast<CriticalResource*>(arg);
    
    while(1)
    {
        presource->_mutex.lock();
        if(presource->_flag==false)
        {
            presource->_cond.wait();//等待,阻塞
        }
        //_flag=true,一号卖票
        if(presource->_tickets>0)
        {
            presource->_tickets--;
            cout<<"windows1 left:tickets "<<presource->_tickets<<endl;
            
            //在解锁unlock之前若有其他操作,如执行return,会死锁
            //一可以采取线程资源清理函数完成
            //二可以采用C++的方式
            /* return nullptr;//???? */

            presource->_mutex.unlock();
            //通知2号窗口卖票,所以要修改条件
            presource->_flag=false;
            presource->_cond.notify();
        }else{
            cout<<"Windows1:tickets has sold out!"<<endl;
            presource->_mutex.unlock();
            break;//票卖完的时候,需要退出线程
        }

    }
    return nullptr;
}

void *windowsSale2(void *arg)
{
    cout<<">> windows2: "<<pthread_self()<<endl;
    CriticalResource *presource=static_cast<CriticalResource*>(arg);
    
    while(1)
    {
        presource->_mutex.lock();
        if(presource->_flag==true)
        {
            presource->_cond.wait();
        }

        //2.2 _flag 为false的时候,执行卖票操作   
        if(presource->_tickets>0)
        {
            presource->_tickets--;
            cout<<"windows2 left:tickets "<<presource->_tickets<<endl;
            presource->_mutex.unlock();
            presource->_flag=true;
            presource->_cond.notify();
        }else{
            cout<<"Windows2:tickets has sold out!"<<endl;
            presource->_mutex.unlock();
            break;//票卖完的时候,需要退出线程
        }
    }
    return nullptr;
}

void test()
{
    CriticalResource resoure(100000);
    pthread_t pthid1,pthid2;
    pthread_create(&pthid1,nullptr,windowsSale1,(void*)&resoure);
    pthread_create(&pthid2,nullptr,windowsSale2,(void*)&resoure);
    
    cout<<"> main thread:"<<pthread_self()<<endl;

    pthread_join(pthid1,nullptr);
    pthread_join(pthid2,nullptr);
}

int main()
{   
    test();
    return 0;
}

 

 

 

Test3.cc

两个线程卖票,可以用C++去解决解锁之前出现的死锁问题

/*  autor:liulei  */
/*  C++           */
#include "Condition.hpp"
#include <iostream>

using std::cout;
using std::endl;

struct CriticalResource
{
    CriticalResource()=default;

    //构造函数完成对象的初始化
    CriticalResource(long tickets)
    : _tickets(tickets)
    , _mutex()
    , _cond(_mutex)
    {}

    long _tickets=1000;
    bool _flag=false;
    wd::MutexLock _mutex;
    wd::Condition _cond{_mutex};
};

/*1号窗口和2号窗口交替卖票*/
//1号卖完了通知2号卖,2号卖完了通知1号卖
//  _flag=true,一号卖,否则一号等待
// _flag=flase,二号卖,否则二号等待
void *windowsSale1(void *arg)
{
    cout<<">>>> windows1: "<<pthread_self()<<endl;
    CriticalResource *presource=static_cast<CriticalResource*>(arg);
    
    while(1)
    {
        /* presource->_mutex.lock(); */
        
        wd::MutexLockGuard mlg(presource->_mutex);
        
        if(presource->_flag==false)
        {
            presource->_cond.wait();//等待,阻塞
        }
        //_flag=true,一号卖票
        if(presource->_tickets>0)
        {
            presource->_tickets--;
            cout<<"windows1 left:tickets "<<presource->_tickets<<endl;
            
            //在解锁unlock之前若有其他操作,如执行return,会死锁
            //一可以采取线程资源清理函数完成
            //二可以采用C++的方式
            return nullptr;//????
            
            /* presource->_mutex.unlock(); */
            //通知2号窗口卖票,所以要修改条件
            presource->_flag=false;
            presource->_cond.notify();
        }else{
            cout<<"Windows1:tickets has sold out!"<<endl;
            /* presource->_mutex.unlock(); */
            break;//票卖完的时候,需要退出线程
        }
    }
    return nullptr;
}

void *windowsSale2(void *arg)
{
    cout<<"windows2: "<<pthread_self()<<endl;
    CriticalResource *presource=static_cast<CriticalResource*>(arg);
    
    while(1)
    {
        /* presource->_mutex.lock(); */
        wd::MutexLockGuard mlg(presource->_mutex);
        
        if(presource->_flag==true)
        {
            presource->_cond.wait();
        }

        //2.2 _flag 为false的时候,执行卖票操作   
        if(presource->_tickets>0)
        {
            presource->_tickets--;
            cout<<"windows2 left:tickets "<<presource->_tickets<<endl;
            presource->_flag=true;
            presource->_cond.notify();
        }else{
            cout<<"Windows2:tickets has sold out!"<<endl;
            /* presource->_mutex.unlock(); */
            break;//票卖完的时候,需要退出线程
        }
    }
    return nullptr;
}

void test()
{
    CriticalResource resoure(100000);
    pthread_t pthid1,pthid2;
    pthread_create(&pthid1,nullptr,windowsSale1,(void*)&resoure);
    pthread_create(&pthid2,nullptr,windowsSale2,(void*)&resoure);
    
    cout<<"> main thread:"<<pthread_self()<<endl;

    pthread_join(pthid1,nullptr);
    pthread_join(pthid2,nullptr);
}

int main()
{   
    test();
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值