muduo庫是高併發的linux網絡編程庫,那麼就一定有mutex對mutex類的封裝,在多線程的編程中,線程間經常會操作一些全局變量,因此我們就需要一些同步的機制,我的上一篇博客condtion算是一種,當然了conditon一般都是和mutex來結合使用。接下來我們看看muduo庫對mutex的封裝
mutex.h
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.h中有對mutex的封裝的Mutexlock類,還有基於Mutexlock封裝的MutexLockGuard
-
Mutexlock類
在mutexlock類中有兩個成員變量:
pthread_mutex_t mutex_ linux互斥鎖
pid_t holder_; 進程id類型mutexlock的構造函數實現對mutex的初始化,和進程id的初始化,默認值爲0
-
MutexLockGuard類
MutexLockGuard類的實現思想有些類似智能指針,通過使用MutexLockGuard,在多線程編程的時候可以防止開發者忘記對鎖的釋放
實現的思想就是,將對互斥鎖的控制交給操作系統,通過一個棧區變量管理一個全局變量,當棧區變量從作用域結束時,系統自動調用該棧區的析構函數從而達到釋放鎖的目的,智能指針就是把一個指針的釋放問題從程序員轉移給系統,只不過是只能指針有
關鍵的地方是,MutexLockGuard類中的成員變量必須是一個&類型的變量,其次在構造函數調用mutexlock的lock函數,析構函數調用mutexlock的unlock函數。
拓展
c++11中mutex,c++11中也對mutex進行封裝,使用方式和muduo庫差不多,同時c++11中也有類似MutexLockGuard的實現,下面我來介紹一下c++11中基於mutex封裝的lock_guard和unique_lock;
lock_guard
#include <thread>
#include <mutex>
#include <vector>
#include <iostream>
#include <algorithm>
std::mutex my_lock;
void add(int &num, int &sum){
while(true){
std::lock_guard<std::mutex> lock(my_lock);
if (num < 100){ //運行條件
num += 1;
sum += num;
}
else { //退出條件
break;
}
//sleep(100);
}
}
int main(){
int sum = 0;
int num = 0;
std::vector<std::thread> ver; //保存線程的vector
for(int i = 0; i < 20; ++i){
std::thread t = std::thread(add, std::ref(num), std::ref(sum));
ver.emplace_back(std::move(t)); //保存線程
}
std::for_each(ver.begin(), ver.end(), std::mem_fn(&std::thread::join)); //join
std::cout << sum << std::endl;
}
同樣上面的代碼使用muduo庫中MutexLockGuard是一樣的。muduo庫的MutexLockGuard和c++11的lock_guard有一個問題,假如我在線程中操作完全局變量後,還有很長的處理邏輯,可能要花很長時間才能結束,例如我在上面sleep(100),這樣就會造成其他線程一直被阻塞,造成效率的下降,所以上面兩種鎖只適合於很短小的局部上鎖。
unique_lock
#include <iostream> // std::cout
#include <thread> // std::thread
#include <mutex> // std::mutex, std::unique_lock
#include <vector>
std::mutex mtx; // mutex for critical section
void add(int &num, int &sum) {
while (true) {
std::unique_lock<std::mutex> lock(my_lock);
if (num < 50) { //運行條件
num += 1;
sum += num;
}
else {
break;
}
lock.unlock(); //釋放鎖
Sleep(10);
lock.lock();//再次上鎖,最後一次上鎖可以不用解鎖
sum += num;
}
}
int main() {
int sum = 0;
int num = 0;
std::vector<std::thread> ver; //保存線程的vector
for (int i = 0; i < 20; ++i) {
std::thread t = std::thread(add, std::ref(num), std::ref(sum));
ver.emplace_back(std::move(t)); //保存線程
}
std::for_each(ver.begin(), ver.end(), std::mem_fn(&std::thread::join)); //join
std::cout << sum << std::endl;
return 0;
}