概述
首先看看Mutex的源码
namespace muduo
{
// Use as data member of a class, eg.
//
// class Foo
// {
// public:
// int size() const;
//
// private:
// mutable MutexLock mutex_;
// std::vector<int> data_ GUARDED_BY(mutex_);
// };
class CAPABILITY("mutex") MutexLock : noncopyable
{
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_;
}
private:
friend class Condition;
class UnassignGuard : noncopyable
{
public:
explicit UnassignGuard(MutexLock& owner)
: owner_(owner)
{
owner_.unassignHolder();
}
~UnassignGuard()
{
owner_.assignHolder();
}
private:
MutexLock& owner_;
};
void unassignHolder()
{
holder_ = 0;
}
void assignHolder()
{
holder_ = CurrentThread::tid();
}
pthread_mutex_t mutex_;
pid_t holder_;
};
// Use as a stack variable, eg.
// int Foo::size() const
// {
// MutexLockGuard lock(mutex_);
// return data_.size();
// }
class SCOPED_CAPABILITY MutexLockGuard : noncopyable
{
public:
explicit MutexLockGuard(MutexLock& mutex) ACQUIRE(mutex)
: mutex_(mutex)
{
mutex_.lock();
}
~MutexLockGuard() RELEASE()
{
mutex_.unlock();
}
private:
MutexLock& mutex_;
};
} // namespace muduo
// Prevent misuse like:
// MutexLockGuard(mutex_);
// A tempory object doesn't hold the lock for long!
#define MutexLockGuard(x) error "Missing guard object name"
#endif // MUDUO_BASE_MUTEX_H
首先看Mutex的成员变量 pthread_mutex_t mutex_; pid_t holder_;
首先holder_是判断这个锁是不是在当前线程被使用。
MutexLock() 就是对mutex进行初始化的函数
isLockedByThisThread() 就是判断互斥量是否被当前线程所使用
lock() 加锁
unlock() 解锁
记得条件变量Condition为mutex的友元
MutexLockGuard是临界区
我们一般把MutexLockGuard定义在栈上,这样离开它的作用域,就自动调用析构函数
所以MutexLockGuard的构造函数为 对mutex_进行加锁,而析构函数为对mutex_进行解锁。
然后我们看Condition类的源代码,只需要看源文件.h
// Use of this source code is governed by a BSD-style license
// that can be found in the License file.
//
// Author: Shuo Chen (chenshuo at chenshuo dot com)
#ifndef MUDUO_BASE_CONDITION_H
#define MUDUO_BASE_CONDITION_H
#include <muduo/base/Mutex.h>
#include <pthread.h>
namespace muduo
{
class Condition : noncopyable
{
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);
void notify()
{
MCHECK(pthread_cond_signal(&pcond_));
}
void notifyAll()
{
MCHECK(pthread_cond_broadcast(&pcond_));
}
private:
MutexLock& mutex_;
pthread_cond_t pcond_;
};
} // namespace muduo
#endif // MUDUO_BASE_CONDITION_H
explicit Condition(MutexLock& mutex):首先构造函数就是 对条件变量进行初始化
~Condition():对条件变量进行销毁
wait():wait函数还是比较重要的,我们要懂得pthread_cond_wait()的原理,首先它会把mutex_锁释放掉,然后在别的函数里,获得锁,然后对资源进行修改,然后此时在重新获得锁mutex_. 所以有一个释放锁和获得锁的过程。
notify()和notifyAll()的区别是:一个通知有资源可用,一个通知所有的线程。
最后一个CountDownLatch是一个重点讲的。
我觉得是对互斥量和条件变量的综合运用。
倒计时(CountDownLatch)它有2个应用:
1:主线程发起多个子进程,等这些子线程各自都完成一定的任务之后,主线程蔡继续执行。通常用于主线程等待多个子线程完成初始化。
2:主线程发起多个子线程,子线程都等待主线程,主线程完成其他一些任务之后通知所有子线程开始执行。通常用于多个子线程等待主线程发出“起跑”命令。
代码:
// Use of this source code is governed by a BSD-style license
// that can be found in the License file.
//
// Author: Shuo Chen (chenshuo at chenshuo dot com)
#include <muduo/base/CountDownLatch.h>
using namespace muduo;
CountDownLatch::CountDownLatch(int count)
: mutex_(),
condition_(mutex_),
count_(count)
{
}
void CountDownLatch::wait()
{
MutexLockGuard lock(mutex_);
while (count_ > 0)
{
condition_.wait();
}
}
void CountDownLatch::countDown()
{
MutexLockGuard lock(mutex_);
--count_;
if (count_ == 0)
{
condition_.notifyAll();
}
}
int CountDownLatch::getCount() const
{
MutexLockGuard lock(mutex_);
return count_;
}
// Use of this source code is governed by a BSD-style license
// that can be found in the License file.
//
// Author: Shuo Chen (chenshuo at chenshuo dot com)
#include <muduo/base/CountDownLatch.h>
using namespace muduo;
CountDownLatch::CountDownLatch(int count)
: mutex_(),
condition_(mutex_),
count_(count)
{
}
void CountDownLatch::wait()
{
MutexLockGuard lock(mutex_);
while (count_ > 0)
{
condition_.wait();
}
}
void CountDownLatch::countDown()
{
MutexLockGuard lock(mutex_);
--count_;
if (count_ == 0)
{
condition_.notifyAll();
}
}
int CountDownLatch::getCount() const
{
MutexLockGuard lock(mutex_);
return count_;
}
然后我们看一个子线程等待主线程的例子:
代码:
#include<muduo/base/CountDownLatch.h>
#include<muduo/base/Thread.h>
#include<boost/bind.hpp>
#include<iostream>
using namespace muduo;
CountDownLatch latch_(1);
void Function()
{
latch_.wait();
printf("Thread ID = %d, Thread name = %sn", CurrentThread::tid(), CurrentThread::name());
}
int main()
{
Thread t1(boost::bind(Function),"Thread 1");
Thread t2(boost::bind(Function),"Thread 2");
t1.start();
t2.start();
printf("main Thread is running,before CountDownn");
latch_.countDown();
sleep(3);
printf("Sub Thread is running,after CountDownn");
t1.join();
t2.join();
return 0;
}
只有主线程发起命令,即latch_.countDown();
子线程才会运行。
运行结果截图:
然后看一个主线程等待子线程的代码:
#include<muduo/base/CountDownLatch.h>
#include<muduo/base/Thread.h>
#include<muduo/base/Atomic.h>
#include<boost/bind.hpp>
#include<muduo/base/Mutex.h>
#include<iostream>
using namespace muduo;
muduo::AtomicInt32 cnt;
CountDownLatch latch_(2);
void Function()
{
latch_.countDown();
cnt.incrementAndGet();
printf("Thread ID = %d, Thread name = %sn", CurrentThread::tid(), CurrentThread::name());
}
int main()
{
Thread t1(boost::bind(Function),"Thread 1");
Thread t2(boost::bind(Function),"Thread 2");
printf("before son child:%dn", cnt.get());
t1.start();
t2.start();
sleep(3);
printf("main wait for son pthread running over.n");
latch_.wait();
printf("son pthread running overn");
printf("After son child:%dn", cnt.get());
t1.join();
t2.join();
return 0;
}
这里是将latch_的值设置为2,那么只有当t1,t2线程执行完毕以后,才会调用主线程,不然一直阻塞在latch_.wait()上。
运行截图:
我们对cnt变量定义的是原子操作,所以经过两次递增,变为2.成功实现,主线程等待子线程
最后
以上就是雪白墨镜为你收集整理的Muduo之Mutex、Condition、CountDownlatch解析及例子讲解的全部内容,希望文章能够帮你解决Muduo之Mutex、Condition、CountDownlatch解析及例子讲解所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复