C++封装POSIX 线程库(一)互斥锁的封装

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zhangxiao93/article/details/52024675

C++封装POSIX 线程库(一)互斥锁的封装

在知乎上有人吐槽说C++11多线程库做的太复杂,建议自己封装一蛤,只要一个下午就搞定了。当然我没有陈硕老师那么大本事,花了几天时间,学习了一下把POSIX Pthread进行简单的封装。


1.互斥锁简介

互斥锁主要用于互斥,互斥是一种竞争关系,用来保护临界资源一次只被一个线程访问。
POSIX Pthread提供下面函数用来操作互斥锁。

int pthread_mutex_init(pthread_mutex_t  *mutex,  const  pthread_mutexattr_t *mutexattr);
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_trylock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
int pthread_mutex_destroy(pthread_mutex_t *mutex);
//返回:
//pthread_mutex_init总是返回0
//其他mutex函数返回0表示成功,非0的错误码表示失败

由于pthread系列函数返回成功的时候都是0,因此,我们可以写一个宏作为一个轻量级的检查手段,来判断处理错误。

#define CHECK(exp) \
    if(!exp) \
    { \
        fprintf(stderr, "File:%s, Line:%d Exp:[" #exp "] is true, abort.\n",__FILE__, __LINE__); abort();\
    }

实际使用的时候只需:

CHECK(!pthread_mutex_lock(&mutex));

2.互斥锁的封装

需要考虑以下几个问题:

a.互斥锁的初始化与销毁。
b.互斥锁的操作:加锁和释放锁。

另外,我们的自己封装的类不应该有赋值和拷贝构造的语义,这一点跟单例模式类似,我们可以使我们的类继承自boost库的noncopyable。

//MutexLock.h

#ifndef __MUTEXLOCK_H__
#define __MUTEXLOCK_H__
#include <iostream>
#include <cstdio>
#include <boost/noncopyable.hpp>
#include <pthread.h>
#include <assert.h>

#define CHECK(exp) \
    if(!exp) \
{ \
    fprintf(stderr, "File:%s, Line:%d Exp:[" #exp "] is true, abort.\n",__FILE__, __LINE__); abort();\
}

class MutexLock : public boost::noncopyable
{
    friend class Condition;//条件变量友元声明
    public:
        MutexLock();
        ~MutexLock();
        void lock();
        void unlock();
        bool isLocking() const 
        {
            return isLocking_;
        }
        pthread_mutex_t *getMutexPtr()
        {
            return &mutex_;
        }
    private:
        void restoreMutexStatus()
        {
            isLocking_=true;
        }
        pthread_mutex_t mutex_;//互斥锁
        bool isLocking_;
};
#endif

这里完成了Thread 类的声明,但是这里还需要一些补充,那就是使用RAII(资源获取即初始化)技术,对MutexLock初始化和析构进行处理:初始化的时候加锁,析构的时候解锁,这就需要我们重新定义一个class MutexLockGuardMutexLock进行操作

//MutexLock.h

class MutexLockGuard:public boost::noncopyable
{
    public:
        MutexLockGuard(MutexLock &mutex):mutex_(mutex){ mutex_.lock();}//构造时加锁
        ~MutexLockGuard()//析构时解锁
        {
            mutex_.unlock();
        }

    private:
        MutexLock &mutex_;
};

下面就要具体实现几个函数了,主要是:
pthread_mutex_init()pthread_mutex_destroy()pthread_mutex_lock()pthread_mutex_unlock()这四个函数的封装:

//MutexLock.cpp

#include "MutexLock.h"
MutexLock::MutexLock():isLocking_(false)
{
    CHECK(!pthread_mutex_init(&mutex_,NULL));
}
MutexLock::~MutexLock()
{
    assert(!isLocking());
    CHECK(!pthread_mutex_destroy(&mutex_));
}

void MutexLock::lock()
{
    CHECK(!pthread_mutex_lock(&mutex_))//先加锁再修改状态,保证以下赋值操作的原子性。
    isLocking_=true;
}

void MutexLock::unlock()
{
    isLocking_=false;//先修改状态在解锁,保证赋值操作的原子性。
    CHECK(!pthread_mutex_unlock(&mutex_));
}

封装以后,我们使用:

MutexLockGurad lock(mutex);

对临界区进行加锁,而只要我们控制好lock变量的生存期,就能控制临界区,例如:

int count=0;
{
    MutexLockGurad lock(mutex);
    count++;
}//临界区
//...
//离开lock的作用域,lock作为栈上变量,自动释放,调用析构函数,同时释放锁。

3.参考

1.http://www.cnblogs.com/inevermore/p/4008382.html
2.《Linux多线程服务端编程—使用muduoC++ 网络库》

展开阅读全文

没有更多推荐了,返回首页