(1)POSIX信號量:提供對共享資源的獨佔式訪問
以下使用未命名信號量作爲包裝類的核心。
class sem
{
private:
sem_t semp; //信號量
public:
sem()
{
//初始化一個信號量,第2個參數=0則表示此信號量爲本進程所有,否則可在多個進程間共享
//第三個參數指定信號量初始值
if(sem_init(&semp, 0, 1) != 0)
{
throw std::exception();
}
}
~sem()
{
//銷燬信號量,釋放其佔用的資源;若銷燬一個正在被其他線程等待的信號量,則會導致不可預期的後果
sem_destroy(&semp);
}
bool wait()
{
//以原子操作的方式:判斷信號量的值,若爲0,則被阻塞,直到值大於0;否則,使信號量的值-1
return sem_wait(&semp) == 0;
}
bool post()
{
//以原子操作的方式:使信號量的值+1
return sem_post(&semp) == 0;
}
};
(2)互斥鎖:防止多線程同時訪問共享資源
class locker
{
private:
pthread_mutex_t mutex; //互斥鎖
public:
locker()
{
//初始化互斥鎖,第二個參數指定互斥鎖屬性
if(pthread_mutex_init(&mutex, NULL) != 0)
{
throw std::exception();
}
}
~locker()
{
//銷燬互斥鎖,釋放其佔用的資源;若此互斥鎖處於被加鎖的狀態,則銷燬它會導致不可預期的後果
pthread_mutex_destroy(&mutex);
}
bool lock()
{
//以原子操作的方式:判斷互斥鎖的狀態,若已被鎖上,則阻塞,直到被解鎖;否則,加鎖
return pthread_mutex_lock(&mutex) == 0;
}
bool unlock()
{
//以原子操作的方式給互斥鎖解鎖
return pthread_mutex_unlock(&mutex) == 0;
}
};
---- 發生死鎖的常見情況?
- 當線程想要申請某資源時,此資源已被本線程所加鎖,因而線程被阻塞,然而此資源能被解鎖的前提是本線程將此資源解鎖,但線程已被阻塞,於是陷入死鎖;
- 當線程想要申請某資源時,此資源已被其他線程所加鎖,因而線程被阻塞,然而此資源能被解鎖的前提是本線程將另一資源解鎖,但線程已被阻塞,於是陷入死鎖。
很顯然,線程發生死鎖的本質在於線程在申請某資源時陷入阻塞,但唯有繼續運行才能使此資源被解鎖,陷入矛盾。
---- 如何避免死鎖?
先大致判斷是否可能發生死鎖,若可能則使用非阻塞的加鎖接口。
當線程無法獲取鎖(即非阻塞的加鎖函數返回失敗)時,可以嘗試着釋放掉已佔有的鎖,過一段時間後再嘗試加鎖。
(3)條件變量:允許多個線程以無競爭的方式等待特定的條件發生
class condvar
{
private:
pthread_mutex_t mutex; //互斥鎖
pthread_cond_t cond; //條件變量
public:
condvar()
{
//初始化互斥鎖
if(pthread_mutex_init(&mutex, NULL) != 0)
{
throw std::exception();
}
//初始化條件變量,第二個參數指定條件變量的屬性
if(pthread_cond_init(&m_cond, NULL) != 0)
{
//若構造失敗,則釋放已分配的資源
pthread_mutex_destroy(&mutex);
throw std::exception();
}
}
~condvar()
{
//銷燬互斥鎖和條件變量
pthread_mutex_destroy(&mutex);
pthread_cond_destroy(&m_cond);
}
bool wait()
{
//先給互斥鎖加鎖
pthread_mutex_lock(&mutex);
//pthread_cond_wait將調用線程放入條件變量的等待序列中,然後將互斥鎖解鎖
//這保證了從pthread_cond_wait開始執行到調用線程被放入條件變量的等待隊列的這段時間內,
//條件變量不會被修改
//這避免錯過條件變量的變化
//pthread_cond_wait成功返回後互斥鎖又被鎖上
int ret = pthread_cond_wait(&m_cond, &mutex);
//最後給互斥鎖解鎖
pthread_mutex_unlock(&mutex);
return ret == 0;
}
bool signal()
{
//喚醒一個等待目標條件變量的線程
return pthread_cond_signal(&m_cond) == 0;
}
};