RAII实现的mutex资源类
為什么80%的碼農都做不了架構師?>>> ??
RAII,指的是Resource Acquisition is Initialization。即使用資源時對資源初始化,使用完畢進行自動釋放。它利用stack上的臨時對象生命期是程序自動管理的這一特點,將我們的資源釋放操作封裝在一個臨時對象中。
當我們使用多線程時,需要保證線程安全,這就需要對資源進行加鎖。Linux下使用pthread_mutex_t實現不可重入。我們可以用RAII的手法對mutex進行封裝。
封裝
class MutexLock { public:MutexLock() {pthread_mutex_init(&mutex_, NULL);cout << "construct of MutexLock" << endl;}~MutexLock() {cout << "deconstruct of MutexLock" << endl;pthread_mutex_destroy(&mutex_);}void lock() {pthread_mutex_lock(&mutex_);//lock不上的線程會被阻塞}void unlock() {pthread_mutex_unlock(&mutex_);}private:MutexLock(const MutexLock &);MutexLock& operator=(const MutexLock &); pthread_mutex_t mutex_; };class MutexLockGuard { public:explicit MutexLockGuard(MutexLock &mutex): mutex_(mutex) {cout << "construct of MutexLockGuard" << endl;mutex_.lock();}~MutexLockGuard() {cout << "deconstruct of MutexLockGuard" << endl;mutex_.unlock();}private:MutexLockGuard(const MutexLock &);MutexLockGuard& operator=(const MutexLock &);MutexLock &mutex_; };MutexLock類的構造函數初始化互斥鎖,析構函數銷毀互斥鎖。它封裝了臨界區,位于lock()和unlock()調用之間。
MutexLockGuard類的構造函數對臨界區進行加鎖操作,進入臨界區,保證了不可重入。析構函數解鎖,退出臨界區。
MutexLockGuard類一般是一個棧對象,它的作用域剛好等于臨界區域。
應用
MutexLock mutex; int cnt = 5;void *f(void *arg){long t_num = (long) arg;while(true){MutexLockGuard lock(mutex);if(cnt>0){usleep(1);cout << "args: " << t_num << " " << "cnt: " << cnt-- << endl; } else{break;} }return NULL; }int main() {pthread_t tid, tid1, tid2, tid3;int ret = pthread_create(&tid, NULL, f,(void*)11);if(ret == -1){perror("create error\n");}ret = pthread_create(&tid1, NULL, f, (void*)22);if(ret == -1){perror("create error\n");}ret = pthread_create(&tid2, NULL, f, (void*)33);if(ret == -1){perror("create error\n");}ret = pthread_create(&tid3, NULL, f, (void*)44);if(ret == -1){perror("create error\n");}pthread_join(tid, NULL);pthread_join(tid1, NULL);pthread_join(tid2, NULL);pthread_join(tid3, NULL);return 0; }程序打開四個線程進行測試,打印結果如下:
construct of MutexLock construct of MutexLockGuardconstruct of MutexLockGuard args: 11 cnt: 5 deconstruct of MutexLockGuardconstruct of MutexLockGuard construct of MutexLockGuardconstruct of MutexLockGuard args: 11 cnt: 4 deconstruct of MutexLockGuardconstruct of MutexLockGuard args: 11 cnt: 3 deconstruct of MutexLockGuardconstruct of MutexLockGuard args: 33 cnt: 2 deconstruct of MutexLockGuardconstruct of MutexLockGuard args: 33 cnt: 1 deconstruct of MutexLockGuardconstruct of MutexLockGuard deconstruct of MutexLockGuarddeconstruct of MutexLockGuard deconstruct of MutexLockGuard deconstruct of MutexLockGuard deconstruct of MutexLock這個結果有點詭異。當四個線程初始化時,生成了兩個MutexLockGuard實例。其中一個獲取到了mutex鎖,另一個進程阻塞。對cnt進行操作后,釋放了mutex鎖。
然后主線程繼續生成另外兩個MutexLockGuard實例。主線程未直接生成四個實例是因為
The main() thread is possibly not creating all threads before it gets preempted by one of its child threads.
接下來發生的事情是:
args: 11獲取鎖,釋放鎖,cnt--
args: 11獲取鎖,釋放鎖,cnt--
args: 33獲取鎖,釋放鎖,cnt--
args: 33獲取鎖,釋放鎖,cnt--
某個進程進入后break。
具體可以參見OS討論。
All the threads construct a MutexLockGuard but only one is permitted to acquire the mutex and proceed (as intended).
However, when that one destroys its MutexLockGuard and releases the mutex, it turns out that it loops around and creates a new MutexLockGuard and acquires the mutex before the system unblocks another thread and allows them to acquire the mutex.
Mutex acquisition is not guaranteed to be fair. The system may act like this in an attempt to prevent spending work switching threads.
其實爭搶到mutex的線程中局部變量MutexLockGuard實例的生存期位于while中,其它未爭搶到mutex的線程阻塞沒有執行到下一個while,所以不調用析構函數。
當所有局部的MutexLockGuard析構后,全局的MutexLock在最后自動析構。
參考
Linux多線程服務端編程
轉載于:https://my.oschina.net/lvyi/blog/425668
總結
以上是生活随笔為你收集整理的RAII实现的mutex资源类的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Linux系统抓包命令tcpdump使用
- 下一篇: mysql表空间配置