互斥鎖
- 初始化
#inlude <pthread.h>
int pthread_mutex_init(pthread_mutex_t *restrict mutex,
const pthread_mutexattr_t *restrict attr);
attr鎖屬性非NULL時:
PTHREAD_MUTEX_TIMED_NP:普通鎖
PTHREAD_MUTEX_RECURSIVE_NP:嵌套鎖(同一鎖可多次加鎖)
PTHREAD_MUTEX_ERRORCHECK_NP:檢錯鎖
PTHREAD_MUTEX_ADAPTIVE_NP:適應(yīng)鎖,釋放后重新競爭
- 銷毀
#inlude <pthread.h>
int pthread_mutex_destroy(pthread_mutex_t *mutex);
- 申請互斥鎖(加鎖)
#inlude <pthread.h>
int pthread_mutex_lock(pthread_mutex_t *mutex);//沒成功(已被加鎖)就阻塞
int pthread_mutex_trylock(pthread_mutex_t *mutex);//沒成功(已被加鎖)就返回
- 釋放互斥鎖(解鎖)
#inlude <pthread.h>
int pthread_mutex_unlock(pthread_mutex_t *mutex);
示例代碼:
#include <pthread.h>
#include <unistd.h>
#include <iostream>
using namespace std;
pthread_mutex_t mutex;
int sum=0;
void *fun1(void *arg)
{
int i=5;
pthread_mutex_lock(&mutex);
while(i>0){
sleep(1);
cout<<"thread1"<<endl;
i--;
sum++;
}
pthread_mutex_unlock(&mutex);
}
void *fun2(void *arg)
{
int i=5;
pthread_mutex_lock(&mutex);
while(i>0){
sleep(1);
cout<<"thread2"<<endl;
i--;
sum--;
}
pthread_mutex_unlock(&mutex);
}
int main()
{
pthread_t thread1,thread2;
pthread_mutex_init(&mutex,NULL);
pthread_create(&thread1,NULL,fun1,NULL);
pthread_create(&thread2,NULL,fun2,NULL);
pthread_join(thread1,NULL);
pthread_join(thread2,NULL);
pthread_mutex_destroy(&mutex);
cout << "sum= "<<sum <<endl;
return 0;
}
運(yùn)行結(jié)果:

若將加鎖解鎖注釋掉后運(yùn)行結(jié)果

條件變量
若有一個臨界資源如一個緩沖區(qū)(字符數(shù)組),當(dāng)緩沖區(qū)為空時線程A寫數(shù)據(jù),當(dāng)緩沖區(qū)有數(shù)據(jù)時B取出數(shù)據(jù)。此時光靠互斥鎖不能滿足要求,就需要Linux另一個同步機(jī)制----條件變量。
- 初始化
#include <pthread.h>
int pthread_cond_init(pthread_cond_t *restrict cond,
const pthread_condattr_t *restrict attr);
- 銷毀
#include <pthread.h>
int pthread_cond_destroy(pthread_cond_t *cond);
- 阻塞等待條件變量(p操作)
#include <pthread.h>
int pthread_cond_wait(pthread_cond_t *restrict cond,
pthread_mutex_t *restrict mutex);
int pthread_cond_timedwait(pthread_cond_t *restrict cond,
pthread_mutex_t *restrict mutex,
const struct timespec *restrict abstime);//在指定時間之內(nèi)等待
wait在調(diào)用的時候, 這個線程會釋放mutex, 并且給這個cond上鎖, 線程被掛起, 不占用CPU,被喚醒的時候這個搶到鎖線程會自動重新上鎖 —— 即重新獲得mutex
無論哪種等待方式,都必須和一個互斥鎖配合,以防止多個線程同時請求pthread_cond_wait()(或pthread_cond_timedwait(),下同)的競爭條件(Race Condition)。mutex互斥鎖必須是普通鎖(PTHREAD_MUTEX_TIMED_NP)或者適應(yīng)鎖(PTHREAD_MUTEX_ADAPTIVE_NP),且在調(diào)用pthread_cond_wait()前必須由本線程加鎖(pthread_mutex_lock()),而在更新條件等待隊(duì)列以前,mutex保持鎖定狀態(tài),并在線程掛起進(jìn)入等待前解鎖。在條件滿足從而離開pthread_cond_wait()之前,mutex將被重新加鎖,以與進(jìn)入pthread_cond_wait()前的加鎖動作對應(yīng)。
————————————————
版權(quán)聲明:本文為CSDN博主「貓已經(jīng)找不回了」的原創(chuàng)文章,遵循 CC 4.0 BY-SA 版權(quán)協(xié)議,轉(zhuǎn)載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/hairetz/java/article/details/4535920
- 互斥鎖加條件變量使用過程
- 臨界區(qū)加鎖
- 掛起等待,等待時釋放鎖
- 被喚醒,加鎖,進(jìn)入臨界區(qū)
- 退出臨界區(qū)時減鎖。
掛起前后鎖的變化:掛起等待前加鎖,掛起等待時解鎖,被喚醒時解鎖
- 通知等待該條件變量的線程(v操作)
int pthread_cond_signal(pthread_cond_t *cond);
int pthread_cond_broadcast(pthread_cond_t *cond);//廣播通知
示例代碼
用條件變量和互斥鎖解決生產(chǎn)者消費(fèi)者問題
#include<iostream>
#include<unistd.h>
#include<stdlib.h>
#include<pthread.h>
using namespace std;
static int count = 0;
// 對于這些pthread中的type要么使用init初始化, 要么使用系統(tǒng)宏初始化
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t cond_not_full = PTHREAD_COND_INITIALIZER;
static pthread_cond_t cond_not_empty = PTHREAD_COND_INITIALIZER;
void *produce(void *arg) {
while(1) {
pthread_mutex_lock(&mutex);
/*
這里寫上while是沒有錯的, 這是因?yàn)楫?dāng)其他的線程調(diào)用signal的時候, 可能會有多個線程同時被喚醒, 但是由于只有一個線程才可以拿到鎖, 其他的還是需要繼續(xù)wait, 所以為了避免“驚群效應(yīng)”, 同時也為了維護(hù)同一個時刻只有一個線程可以進(jìn)入臨界區(qū), 這里使用while
*/
while(count >= 10) {
pthread_cond_wait(&cond_not_full, &mutex);
}
++count;
cout << "produce: count = " << count << endl;
pthread_mutex_unlock(&mutex);
pthread_cond_signal(&cond_not_empty);
}
return NULL;
}
void *consume(void *arg) {
while(1) {
pthread_mutex_lock(&mutex);
while(count <= 0) {
pthread_cond_wait(&cond_not_empty, &mutex);
}
--count;
cout << "consume: count = " << count << endl;
pthread_mutex_unlock(&mutex);
pthread_cond_signal(&cond_not_full);
}
return NULL;
}
int main() {
pthread_t ptid, ctid;
pthread_create(&ptid, NULL, produce, NULL);
pthread_create(&ctid, NULL, consume, NULL);
pthread_join(ptid, NULL);
pthread_join(ctid, NULL);
return 0;
}
信號量
注意此地方是posix信號量,用于線程同步。(SYSTEM V信號量用于進(jìn)程同步)
sem_init(&m_sem, 0, num);
sem_destroy(&m_sem);
sem_wait(&m_sem);//得到資源信號量減一或一直等待
sem_post(&m_sem);//信號量加1
讀寫鎖
pthread_rwlock_init(&rwlock, NULL);
pthread_rwlock_destroy(&rwlock);
pthread_rwlock_rdlock(&rwlock);
pthread_rwlock_wrlock(&rwlock);
pthread_rwlock_unlock(&rwlock);
自旋鎖
(忙等而不是阻塞等,用戶層不常用)
pthread_spin_init(&m_spin, NULL);
pthread_spin_destroy(&m_spin);
pthread_spin_lock(&m_spin);
pthread_spin_unlock(&m_spin);
pthread_spin_trylock(&m_spin);