在windows中,為了讓多個線程達到同步的目的,在對於全域變數等大家都要用的資源的使用上,通常得保證同時只能由一個線程在用,一個線程沒有宣布對它的釋放之前,不能夠給其他線程使用這個變數。在windows裡,我們可以用時EnterCriticalSection()和LeaveCriticalSection()函數.那麼在linux裡,有什麼類似的機制呢?
這裡介紹互斥鎖。
1.申請一個互斥鎖
pthread_mutex_t mutex; //申請一個互斥鎖
你可以聲明多個互斥量。
在聲明該變數後,你需要調用pthread_mutex_init()來建立該變數。pthread_mutex_init的格式如下:
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr);
第一個參數,mutext,也就是你之前聲明的那個互斥量,第二個參數為該互斥量的屬性。屬性定義如下:
互斥量分為下面三種:
l 快速型(PTHREAD_MUTEX_FAST_NP)。這種類型也是預設的類型。該線程的行為正如上面所說的。
l 遞迴型(PTHREAD_MUTEX_RECURSIVE_NP)。如果遇到我們上面所提到的死結情況,同一線程迴圈給互斥量上鎖,那麼系統將會知道該上鎖行為來自同一線程,那麼就會同意線程給該互斥量上鎖。
l 錯誤偵測型(PTHREAD_MUTEX_ERRORCHECK_NP)。如果該互斥量已經被上鎖,那麼後續的上鎖將會失敗而不會阻塞,pthread_mutex_lock()操作將會返回EDEADLK。
可以通過函數
注意以下語句可以做到將一個互斥鎖快速初始化為快速型。
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
2.銷毀一個互斥鎖
pthread_mutex_destroy()用於登出一個互斥鎖,API定義如下:
int pthread_mutex_destroy(pthread_mutex_t *mutex)
銷毀一個互斥鎖即意味著釋放它所佔用的資源,且要求鎖當前處於開放狀態。由於在Linux中,互斥鎖並不佔用任何資源,因此LinuxThreads中的pthread_mutex_destroy()除了檢查鎖狀態以外(鎖定狀態則返回EBUSY)沒有其他動作。
3.上鎖(相當於windows下的EnterCriticalSection)
在建立該互斥量之後,你便可以使用它了。要得到互斥量,你需要調用下面的函數:
int pthread_mutex_lock(pthread_mutex_t *mutex);
該函數用來給互斥量上鎖。互斥量一旦被上鎖後,其他線程如果想給該互斥量上鎖,那麼就會阻塞在這個操作上。如果在此之前該互斥量已經被其他線程上鎖,那麼該操作將會一直阻塞在這個地方,直到獲得該鎖為止。
在得到互斥量後,你就可以進入關鍵代碼區了。
4.解鎖(相當於windows下的LeaveCriticalSection)
在操作完成後,你必須調用下面的函數來給互斥量解鎖,也就是前面所說的釋放。這樣其他等待該鎖的線程才有機會獲得該鎖,否則其他線程將會永遠阻塞。
int pthread_mutex_unlock(pthread_mutex_t *mutex);
5.pthread_mutex_trylock
如果我們不想一直阻塞在這個地方,那麼可以調用下面函數:
int pthread_mutex_trylock(pthread_mutex_t *mutex)
如果此時互斥量沒有被上鎖,那麼pthread_mutex_trylock()將會返回0,並會對該互斥量上鎖。如果互斥量已經被上鎖,那麼會立刻返回EBUSY。
使用範例程式碼如下:
#include <malloc.h>
#include <pthread.h>
struct job {
/* Link field for linked list. */
struct job* next;
/* Other fields describing work to be done */
};
/* A linked list of pending jobs. */
struct job* job_queue;
/* A mutex protecting job_queue. */
pthread_mutex_t job_queue_mutex = PTHREAD_MUTEX_INITIALIZER;
/* Process queued jobs until the queue is empty. */
void* thread_function (void* arg)
{
while (1) {
struct job* next_job;
/* Lock the mutex on the job queue. */
pthread_mutex_lock (&job_queue_mutex);
/* Now it’s safe to check if the queue is empty. */
if (job_queue == NULL)
next_job = NULL;
else {
/* Get the next available job. */
next_job = job_queue;
/* Remove this job from the list. */
job_queue = job_queue->next;
}
/* Unlock the mutex on the job queue because we’re done with the
queue for now. */
pthread_mutex_unlock (&job_queue_mutex);
/* Was the queue empty? If so, end the thread. */
if (next_job == NULL)
break;
/* Carry out the work. */
process_job (next_job);
/* Clean up. */
free (next_job);
}
return NULL;
}