muduo源代码分析1:一个线程安全的Counter示例

现在开始讲《Linux多线程服务端编程:使用muduoC++网络库》一书的代码,对服务器多线程C++编程做一系列的介绍,首先本节将介绍最简单的一个线程安全示例Counter,其实现的是一个线程安全的计数器,首先下载书中源代码:

git clone http://github.com/chenshuo/recipes.git

代码是基于moduo网络库和标准boost库实现,故首先要安装boost和moduo,boost库的安装参看boost安装。

示例代码 Counter.cc在目录/recipes/thread/test下,首先介绍下如何编译Counter.cc,Counter.cc的编译还涉及到3个其他文件,均在目录/recipes/thread/下,分别为Mutex.h、Thread.h和Thread.cc,makefile内容如下:

CXX = g++
DEBUG = -g -O2
CFLAGS = $(DEBUG) -Wall -c
RM = rm -rf
LIBS = -lpthread -lboost_system -lboost_thread
TARGET = Counter
OBJS =Counter.o Thread.o
$(TARGET) : $(OBJS)
	$(CXX) $^ -o $@ $(LIBS)
Counter.o : Counter.cc
	$(CXX) $(CFLAGS) $< -o $@
Thread.o : ../Thread.cc
	$(CXX) $(CFLAGS) $< -o $@
clean:
	$(RM) $(TARGET) *.o

注意这里涉及boost库和多线程的编译,需要连接静态文件:-lpthread -lboost_system -lboost_thread。

下面来看代码,首先看Counter.cc的代码:

#include "../Mutex.h"
using muduo::MutexLock;
using muduo::MutexLockGuard;

// A thread-safe counter
class Counter : boost::noncopyable
{
  // copy-ctor and assignment should be private by default for a class.
 public:
  Counter() : value_(0) {}
  Counter& operator=(const Counter& rhs);

  int64_t value() const;
  int64_t getAndIncrease();

  friend void swap(Counter& a, Counter& b);

 private:
  mutable MutexLock mutex_;
  int64_t value_;
};

int64_t Counter::value() const
{
  MutexLockGuard lock(mutex_);
  return value_;
}

int64_t Counter::getAndIncrease()
{
  MutexLockGuard lock(mutex_);
  int64_t ret = value_++;
  return ret;
}

void swap(Counter& a, Counter& b)
{
  MutexLockGuard aLock(a.mutex_);  // potential dead lock
  MutexLockGuard bLock(b.mutex_);
  int64_t value = a.value_;
  a.value_ = b.value_;
  b.value_ = value;
}

Counter& Counter::operator=(const Counter& rhs)
{
  if (this == &rhs)
    return *this;

  MutexLockGuard myLock(mutex_);  // potential dead lock
  MutexLockGuard itsLock(rhs.mutex_);
  value_ = rhs.value_;
  return *this;
}

int main()
{
  Counter c;
  c.getAndIncrease();
}

类Counter继承了boost::noncopyable类,作用是禁用拷贝赋值函数和赋值运算。这个例子很简单,对成员变量value进行计数,可以返回value值,可以递加value的值,且可以交换两个对象的成员value的值。首先看函数value():

int64_t Counter::value() const
{
  MutexLockGuard lock(mutex_);
  return value_;
}

声明为const有两个作用:1.声明为const,才能被const对象调用;2.声明为const,不允许修改成员变量。这里用到了类MutexLockGuard,其定义在Mutex.h文件中:

class MutexLockGuard : boost::noncopyable
{
 public:
  explicit MutexLockGuard(MutexLock& mutex) : mutex_(mutex)
  {
    mutex_.lock();
  }

  ~MutexLockGuard()
  {
    mutex_.unlock();
  }

 private:

  MutexLock& mutex_;
};

主要用到了MutexLock类,其定义同样在Mutex.h文件中:

class MutexLock : boost::noncopyable
{
 public:
  MutexLock()
    : holder_(0)
  {
    pthread_mutex_init(&mutex_, NULL);
  }

  ~MutexLock()
  {
    assert(holder_ == 0);
    pthread_mutex_destroy(&mutex_);
  }

  bool isLockedByThisThread()
  {
    return holder_ == CurrentThread::tid();
  }

  void assertLocked()
  {
    assert(isLockedByThisThread());
  }

  // internal usage

  void lock()
  {
    pthread_mutex_lock(&mutex_);
    holder_ = CurrentThread::tid();
  }

  void unlock()
  {
    holder_ = 0;
    pthread_mutex_unlock(&mutex_);
  }

  pthread_mutex_t* getPthreadMutex() /* non-const */
  {
    return &mutex_;
  }

 private:

  pthread_mutex_t mutex_;
  pid_t holder_;
};

这里定义了线程互斥变量pthread_mutex_t mutex_,holder_在锁定的时候保存锁定线程的线程id,调用lock锁定互斥变量,调用unlock解锁互斥变量,holder_重新置为0。我们再回到MutexLockGuard的定义,可以看到MutexLockGuard通过构造函数传入一个互斥变量,并锁定该互斥变量,在析构的时候会解锁该互斥变量。现在再看Value函数就很容易理解了,MutexLockGuard定义局部变量lock,此时会调用构造函数锁定mutex_,当value函数执行完成后,局部变量lock生命周期结束,调用析构函数释放mutex_。这里注意两点,一点是互斥成员变量声明为mutex_,这样即便在const的函数中其值也是可变的;swap函数定义为友元函数,其本身不是类成员函数,但由于声明为友元,故可以访问类的私有变量。这是最简答的一个多线程加锁的例子,但仍然是有问题的,例如Counter是动态创建的,且通过一个指针来访问,那么解析这个对象的时候是否有线程正在执行该对象是未知的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值