MutexLock类
MutexLock类的实现
class MutexLock : boost::noncopyable
{
public:
MutexLock()
: holder_(0)
{
int ret = pthread_mutex_init(&mutex_, NULL);
assert(ret == 0); (void) ret;
}
~MutexLock()
{
assert(holder_ == 0);
int ret = pthread_mutex_destroy(&mutex_);
assert(ret == 0); (void) ret;
}
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_;
};
MutexLockGuard类
MutexLockGuard类的实现
class MutexLockGuard : boost::noncopyable
{
public:
explicit MutexLockGuard(MutexLock& mutex)
: mutex_(mutex)
{
mutex_.lock();
}
~MutexLockGuard()
{
mutex_.unlock();
}
private:
MutexLock& mutex_; // 此处是引用,MutexLockGuard析构时,mutex_的生存期并没有结束
};
MutexLockGuard类使用RAII技法
封装,在对象构造时获取资源,在对象析构的时候释放资源
。我们把管理一份资源的责任托管给了一个对象
。平时更常用MutexLockGuard,作用域内加锁,可以防止忘记解锁。
Condition类
Condition类的实现
class Condition : boost::noncopyable
{
public:
explicit Condition(MutexLock& mutex)
: mutex_(mutex)
{
pthread_cond_init(&pcond_, NULL);
}
~Condition()
{
pthread_cond_destroy(&pcond_);
}
void wait()
{
pthread_cond_wait(&pcond_, mutex_.getPthreadMutex());
}
// returns true if time out, false otherwise.
bool waitForSeconds(int seconds);
void notify()
{
pthread_cond_signal(&pcond_);
}
void notifyAll()
{
pthread_cond_broadcast(&pcond_);
}
private:
MutexLock& mutex_;
pthread_cond_t pcond_;
};
条件变量与互斥锁的通常情况下配合使用
explicit Condition(MutexLock& mutex)
: mutex_(mutex)
{
pthread_cond_init(&pcond_, NULL);
}
条件变量的正确使用方式
某个线程:
加锁 // 加锁,防止条件被其他线程更改
while (条件)
wait();
解锁
另一个线程:
加锁
更改条件
通知notify(可以移到锁外)
解锁
pthread_cond_wait(&pcond_, mutex_.getPthreadMutex());
等待线程的三个步骤:
- 解锁;如果没有解锁,
其他线程,没法进入临界区
,修改条件,条件将始终没法成立。 - 等待通知;
- 得到通知返回前重新加锁; 重新加锁,是
下面的解锁操作对应起来
CountDownLatch类
CountDownLatch类既可以用于所有子线程等待主线程发起起跑,也可以用于主线程等待子线程初始化完毕才开始工作。
CountDownLatch类的部分实现
explicit CountDownLatch(int count);
void CountDownLatch::wait()
{
MutexLockGuard lock(mutex_);
while (count_ > 0) {
condition_.wait();
}
}
void CountDownLatch::countDown()
{
MutexLockGuard lock(mutex_);
--count_;
if (count_ == 0) {
condition_.notifyAll();
}
}
主线程发起起跑
#include <muduo/base/CountDownLatch.h>
#include <muduo/base/Thread.h>
#include <boost/bind.hpp>
#include <boost/ptr_container/ptr_vector.hpp>
#include <string>
#include <stdio.h>
using namespace muduo;
class Test
{
public:
Test(int numThreads)
: latch_(1),
threads_(numThreads)
{
for (int i = 0; i < numThreads; ++i)
{
char name[32];
snprintf(name, sizeof name, "work thread %d", i);
threads_.push_back(new muduo::Thread(
boost::bind(&Test::threadFunc, this), muduo::string(name)));
}
for_each(threads_.begin(), threads_.end(), boost::bind(&Thread::start, _1));
}
void run()
{
latch_.countDown();
}
void joinAll()
{
for_each(threads_.begin(), threads_.end(), boost::bind(&Thread::join, _1));
}
private:
void threadFunc()
{
latch_.wait();
printf("tid=%d, %s started\n",
CurrentThread::tid(),
CurrentThread::name());
printf("tid=%d, %s stopped\n",
CurrentThread::tid(),
CurrentThread::name());
}
CountDownLatch latch_;
boost::ptr_vector<Thread> threads_;
};
int main()
{
printf("pid=%d, tid=%d\n", ::getpid(), CurrentThread::tid());
Test t(3);
sleep(3);
printf("pid=%d, tid=%d %s running ...\n", ::getpid(), CurrentThread::tid(), CurrentThread::name());
t.run();
t.joinAll();
printf("number of created threads %d\n", Thread::numCreated());
}
程序输出
```
可以看到其他三个线程一直等到主线程睡眠完执行run(),在里面执行latch_.countDown()将计数减为0,进而执行notifyall唤醒后,才开始执行下来。
#### 主线程等待子线程
```C++
#include <muduo/base/CountDownLatch.h>
#include <muduo/base/Thread.h>
#include <boost/bind.hpp>
#include <boost/ptr_container/ptr_vector.hpp>
#include <string>
#include <stdio.h>
using namespace muduo;
class Test
{
public:
Test(int numThreads)
: latch_(numThreads),
threads_(numThreads)
{
for (int i = 0; i < numThreads; ++i)
{
char name[32];
snprintf(name, sizeof name, "work thread %d", i);
threads_.push_back(new muduo::Thread(
boost::bind(&Test::threadFunc, this), muduo::string(name)));
}
for_each(threads_.begin(), threads_.end(), boost::bind(&muduo::Thread::start, _1));
}
void wait()
{
latch_.wait();
}
void joinAll()
{
for_each(threads_.begin(), threads_.end(), boost::bind(&Thread::join, _1));
}
private:
void threadFunc()
{
sleep(3);
printf("tid=%d, %s started\n",
CurrentThread::tid(),
CurrentThread::name());
latch_.countDown();
printf("tid=%d, %s stopped\n",
CurrentThread::tid(),
CurrentThread::name());
}
CountDownLatch latch_;
boost::ptr_vector<Thread> threads_;
};
int main()
{
printf("pid=%d, tid=%d\n", ::getpid(), CurrentThread::tid());
Test t(3);
t.wait();
printf("pid=%d, tid=%d %s running ...\n", ::getpid(), CurrentThread::tid(), CurrentThread::name());
t.joinAll();
printf("number of created threads %d\n", Thread::numCreated());
}
程序输出
可以看出当其他三个线程都启动后,各自执行一次latch_.countDown(),主线程wait() 返回继续执行下去。
ptr_vector小知识
boost::ptr_vector专门用于动态分配的对象
,它使用起来更容易也更高效。容器在析构的时候,会自动清理指针