muduo_base代码剖析之Thread/Mutex/MutexLockGuard /Condition/CountDownLatch

版权声明:guojawee https://blog.csdn.net/weixin_36750623/article/details/84309778

(1) 线程:Thread、CurrentThread

Thread.h、Thread.cc代码解读

在这里插入图片描述
功能介绍:

  1. 创建线程时,把线程函数当作形参传递进去:muduo::Thread t(std::bind(threadFunc2, 42), “thread for free function with argument”);
    说明:线程形参func_是void func()类型的,可以使用boost::bind进行适配
  2. 启动线程,使线程回调线程函数func_:t.start()
  3. 使线程不先退出:t.join

源代码分析:Thread类

class Thread : noncopyable
{
 public:
  typedef std::function<void ()> ThreadFunc; //线程函数类型
  
  //创建线程时,形参:func是线程函数,当start()时,func()开始执行
  explicit Thread(ThreadFunc func, const string& n)
    : started_(false),joined_(false),pthreadId_(0),tid_(0),
    func_(std::move(func)), //线程函数
    name_(n),latch_(1) 
  {
    setDefaultName();
  }

  ~Thread();

  void start() //最后调用了传进来的func()函数
  {//调用顺序:start()-->pthread_create()-->startThread()-->runInThread()-->func_()
	  assert(!started_);
	  started_ = true;
	  // FIXME: move(func_)
	  detail::ThreadData* data = new detail::ThreadData(func_, name_, &tid_, &latch_);
	  if (pthread_create(&pthreadId_, NULL, &detail::startThread, data))
	  {
	    started_ = false;
	    delete data; // or no delete?
	    LOG_SYSFATAL << "Failed in pthread_create";
	  }
	  else
	  {
	    latch_.wait();
	    assert(tid_ > 0);
	  }
  }
  
  int join(); 
  bool started() const { return started_; }
  pid_t tid() const { return tid_; }
  const string& name() const { return name_; }
  static int numCreated() { return numCreated_.get(); }
private:
  void setDefaultName();

  bool       started_;
  bool       joined_;
  pthread_t  pthreadId_;
  pid_t      tid_;
  ThreadFunc func_; //线程函数
  string     name_;
  CountDownLatch latch_;

  static AtomicInt32 numCreated_;
};

测试代码 ./test/Thread_test.c

#include <muduo/base/Thread.h>
#include <muduo/base/CurrentThread.h>

#include <string>
#include <stdio.h>
#include <unistd.h>

void threadFunc() 
{
  printf("tid=%d\n", muduo::CurrentThread::tid());
}

void threadFunc2(int x)
{
  printf("tid=%d, x=%d\n", muduo::CurrentThread::tid(), x);
}

class Foo
{
 public:
  explicit Foo(double x)
    : x_(x)
  {
  }

  void memberFunc()
  {
    printf("tid=%d, Foo::x_=%f\n", muduo::CurrentThread::tid(), x_);
  }

  void memberFunc2(const std::string& text)
  {
    printf("tid=%d, Foo::x_=%f, text=%s\n", muduo::CurrentThread::tid(), x_, text.c_str());
  }

 private:
  double x_;
};

int main()
{
  printf("pid=%d, tid=%d\n", ::getpid(), muduo::CurrentThread::tid());

  //threadFunc无参,无需适配
  muduo::Thread t1(threadFunc); 
  t1.start();
  printf("t1.tid=%d\n", t1.tid());
  t1.join();

  //threadFunc一个参数,需适配
  muduo::Thread t2(std::bind(threadFunc2, 42),
                   "thread for free function with argument");
  t2.start();
  printf("t2.tid=%d\n", t2.tid());
  t2.join();

  //Foo对象的成员函数memberFunc
  Foo foo(87.53);
  muduo::Thread t3(std::bind(&Foo::memberFunc, &foo),
                   "thread for member function without argument");
  t3.start();
  t3.join();
  //Foo对象的成员函数memberFunc2
  muduo::Thread t4(std::bind(&Foo::memberFunc2, std::ref(foo), std::string("Shuo Chen")));
  t4.start();
  t4.join();

  printf("number of created threads %d\n", muduo::Thread::numCreated());
}

CurrentThread.h

namespace CurrentThread
{
# __thread修饰的变量是线程局部存储的,每个线程都有一份
__thread int t_cachedTid = 0; # 线程真实pid(tid)的缓存,是为
     #了提高获取tid的效率,较少::syscall(SYS_gettid)系统调用的次数
__thread char t_tidString[32]; # tid的字符串表示形式
__thread int t_tidStringLength = 6;
__thread const char* t_threadName = "unknown"; #每个线程的名称

(2)互斥锁:MutexLock、MutexLockGuard

MutexLock

功能:对Linux C下的互斥锁Mutex进行了封装,功能一致
在这里插入图片描述

class CAPABILITY("mutex") MutexLock : noncopyable
{
private:
  pthread_mutex_t mutex_;
  pid_t holder_; //当前拥有该锁的真实的线程id
public:
  MutexLock()
    : holder_(0)
  {
    MCHECK(pthread_mutex_init(&mutex_, NULL));
  }

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

  // must be called when locked, i.e. for assertion
  bool isLockedByThisThread() const // 是否当前线程拥有该锁
  {
    return holder_ == CurrentThread::tid();
  }

  void assertLocked() const ASSERT_CAPABILITY(this)
  {
    assert(isLockedByThisThread());
  }

  // internal usage

  void lock() ACQUIRE() //加锁
  {
    MCHECK(pthread_mutex_lock(&mutex_));
    assignHolder();
  }

  void unlock() RELEASE()
  {
    unassignHolder();
    MCHECK(pthread_mutex_unlock(&mutex_));
  }

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

MutexLockGuard

与MutexLock不同点:当MutexLockGuard类型的锁对象被销毁时,将调用析构函数,导致加的锁将自动释放
在这里插入图片描述

class SCOPED_CAPABILITY MutexLockGuard : noncopyable
{
 public:
  explicit MutexLockGuard(MutexLock& mutex) ACQUIRE(mutex)
    : mutex_(mutex) // 构造时,对mutex_加锁
  {
    mutex_.lock();
  }
  ~MutexLockGuard() RELEASE() //析构时,对mutex_解锁
  {
    mutex_.unlock();
  }
 private:
  MutexLock& mutex_;
};

// 宏:不允许定义一个匿名的MutexLockGuard对象
#define MutexLockGuard(x) error "Missing guard object name"

示例代码

#include <muduo/base/Mutex.h>
#include <muduo/base/Thread.h>
#include <muduo/base/Timestamp.h>

#include <vector>
#include <stdio.h>

using namespace muduo;
using namespace std;

MutexLock g_mutex;
vector<int> g_vec;
const int kCount = 10*1000*1000;

void threadFunc()
{
  for (int i = 0; i < kCount; ++i)
  {
    MutexLockGuard lock(g_mutex); //构造函数中,加锁
    g_vec.push_back(i); 
  } //函数退出,调用MutexLockGuard析构函数,解锁(因此不需要手动的解锁)
}
int main()
{
  const int kMaxThreads = 8;
  g_vec.reserve(kMaxThreads * kCount);

  //单个线程不加锁
  Timestamp start(Timestamp::now());
  for (int i = 0; i < kCount; ++i)
  {
    g_vec.push_back(i);
  }

  printf("single thread without lock %f\n", timeDifference(Timestamp::now(), start));

  //单个线程加锁
  start = Timestamp::now();
  threadFunc();
  printf("single thread with lock %f\n", timeDifference(Timestamp::now(), start));

  //分别创建1、2、3、4、5、6、7个线程,统计时间开销
  for (int nthreads = 1; nthreads < kMaxThreads; ++nthreads)
  {
    std::vector<std::unique_ptr<Thread>> threads;
    g_vec.clear();
    start = Timestamp::now();
    for (int i = 0; i < nthreads; ++i)
    {
      threads.emplace_back(new Thread(&threadFunc));
      threads.back()->start();
    }
    for (int i = 0; i < nthreads; ++i)
    {
      threads[i]->join();
    }
    printf("%d thread(s) with lock %f\n", nthreads, timeDifference(Timestamp::now(), start));
  }
}

(3) 条件变量:Condition、CountDownLatch

Condition

主要功能:对Linux C下的条件变量Condition进行了封装,功能一致

class Condition : noncopyable
{
 private:
  MutexLock& mutex_;  // 条件变量要配合互斥锁一起使用
  pthread_cond_t pcond_;
 public:
  explicit Condition(MutexLock& mutex)
    : mutex_(mutex)
  {
    MCHECK(pthread_cond_init(&pcond_, NULL));
  }

  ~Condition()
  {
    MCHECK(pthread_cond_destroy(&pcond_));
  }

  void wait()
  {
    MutexLock::UnassignGuard ug(mutex_);
    MCHECK(pthread_cond_wait(&pcond_, mutex_.getPthreadMutex()));
  }

  // returns true if time out, false otherwise.
  bool waitForSeconds(double seconds) // 调用了pthread_cond_timedwait
  {
    struct timespec abstime;
    // FIXME: use CLOCK_MONOTONIC or CLOCK_MONOTONIC_RAW to prevent time rewind.
    clock_gettime(CLOCK_REALTIME, &abstime);

    const int64_t kNanoSecondsPerSecond = 1000000000;
    int64_t nanoseconds = static_cast<int64_t>(seconds * kNanoSecondsPerSecond);

    abstime.tv_sec += static_cast<time_t>((abstime.tv_nsec + nanoseconds) / kNanoSecondsPerSecond);
    abstime.tv_nsec = static_cast<long>((abstime.tv_nsec + nanoseconds) % kNanoSecondsPerSecond);

    MutexLock::UnassignGuard ug(mutex_);
    return ETIMEDOUT == pthread_cond_timedwait(&pcond_, mutex_.getPthreadMutex(), &abstime);
  }

  void notify()
  {
    MCHECK(pthread_cond_signal(&pcond_));
  }

  void notifyAll()
  {
    MCHECK(pthread_cond_broadcast(&pcond_));
  }
};

CountDownLatch

CountDownLatch类,对条件变量类进行了封装

  1. 使用条件变量Condition,可以使得线程阻塞在一个条件上
  2. 使用CountDownLatch,可以使得线程阻塞在count_变量是否为0上。那么,哪个线程将会阻塞在count!=0条件上呢?答案:调用wait()函数的线程
class CountDownLatch : noncopyable
{
private:
  mutable MutexLock mutex_;
  Condition condition_ ;
  int count_ ;
public:
  explicit CountDownLatch::CountDownLatch(int count)
  : mutex_(),condition_(mutex_),count_(count)
  {
  }

  //调用wait()函数的线程,当count_>0时将会阻塞在wait()函数处
  void wait() 
  {
    MutexLockGuard lock(mutex_);
    while (count_ > 0) 
    {
      condition_.wait(); 
    }
  }
  void countDown()
  {
    MutexLockGuard lock(mutex_);
    --count_;
    if (count_ == 0)
    {
      condition_.notifyAll();
    }
  }

  int getCount() const
  {
    MutexLockGuard lock(mutex_);
    return count_;
  }
};

猜你喜欢

转载自blog.csdn.net/weixin_36750623/article/details/84309778