Linux 下C語言多線程編程--互斥鎖

互斥鎖

  • 互斥鎖用來保證一段時間內只有一個線程在執行一段代碼(保證共享數據的完整性)

  • 互斥鎖變量

    typedef union{
     	struct __pthread_mutex_s __data;
    	char __size[__SIZEOF_PTHREAD_MUTEX_T];
    	long int __align;
    } pthread_mutex_t;
    
  • 互斥鎖的生成

    /* Initialize a mutex.  */
    extern int pthread_mutex_init (pthread_mutex_t *__mutex,
    			       const pthread_mutexattr_t *__mutexattr)
    	 __THROW __nonnull ((1));
    

    用於動態創建一個互斥鎖,第一個參數爲互斥鎖指針,第二個參數爲互斥鎖屬性(通常傳NULL表示默認屬性)

互斥鎖屬性

  • 屬性結構

    /* Data structures for mutex handling.  The structure of the attribute
    type is not exposed on purpose.  */
    typedef union{
     	char __size[__SIZEOF_PTHREAD_MUTEXATTR_T];
    	int __align;
    } pthread_mutexattr_t;
    

    互斥鎖屬性使用上面的聯合體存放,通過函數pthread_mutexattr_setpshared()設置範圍屬性,

  • 範圍屬性

    /* Process shared or private flag.  */
    enum{
    	PTHREAD_PROCESS_PRIVATE,//同進程中線程同步
    	#define PTHREAD_PROCESS_PRIVATE PTHREAD_PROCESS_PRIVATE
    	PTHREAD_PROCESS_SHARED //不同進程中的線程同步
    	#define PTHREAD_PROCESS_SHARED  PTHREAD_PROCESS_SHARED
    };
    
  • 類型屬性
    通過函數pthread_mutexattr_settype()(通常使用默認屬性PTHREAD_MUTEX_DEFAULT

    /* Mutex types.  */
    enum{
    	//缺省值,普通鎖,當一個線程加鎖以後,其餘請求鎖的線程將會形成一個等待隊列
    	//並在解鎖後按照先後順序獲得鎖,資源分配公平
    	PTHREAD_MUTEX_TIMED_NP,
    	//嵌套鎖,允許同一線程對同一鎖成功獲得多次,並通過多次unlock解鎖
    	//如果是不同線程請求,則在加鎖線程解鎖時重新競爭
    	PTHREAD_MUTEX_RECURSIVE_NP,
    	//檢錯鎖,如果同一線程請求同一個鎖,則返回EDEALK
    	//否則與普通鎖類型動作相同,這樣保證當不允許多次時,不會出現最簡單的死鎖
    	PTHREAD_MUTEX_ERRORCHECK_NP,
    	//適應鎖,動作最簡單的類型,僅等待解鎖以後重新競爭
    	PTHREAD_MUTEX_ADAPTIVE_NP
    	#if defined __USE_UNIX98 || defined __USE_XOPEN2K8
    	 ,
    	PTHREAD_MUTEX_NORMAL = PTHREAD_MUTEX_TIMED_NP,
    	PTHREAD_MUTEX_RECURSIVE = PTHREAD_MUTEX_RECURSIVE_NP,
    	PTHREAD_MUTEX_ERRORCHECK = PTHREAD_MUTEX_ERRORCHECK_NP,
    	PTHREAD_MUTEX_DEFAULT = PTHREAD_MUTEX_NORMAL
    	#endif
    	#ifdef __USE_GNU
    	 /* For compatibility.  */
    	, PTHREAD_MUTEX_FAST_NP = PTHREAD_MUTEX_TIMED_NP
    	#endif
    };
    
  • Demo

    static void init_thread_mutex(void) {
    	pthread_mutexattr_t mutex_attr;
    	//PTHREAD_PROCESS_SHARED
    	pthread_mutexattr_setpshared(&mutex_attr, PTHREAD_PROCESS_PRIVATE);
    	pthread_mutexattr_settype(&mutex_attr,PTHREAD_MUTEX_DEFAULT);
    	//使用上面的屬性初始化thread_data_mutex互斥鎖
    	pthread_mutex_init(&thread_data_mutex, &mutex_attr); 
    }
    

上鎖操作

  • 加鎖lock ()、解鎖unlock()、測試加鎖trylock()不論是哪種類型的鎖,都不可能被兩個不同的線程得到,而必須等待解鎖,對於普通鎖適應鎖,解鎖者可以說同進程內的任何線程,而對於檢錯鎖必須由加鎖者解鎖,嵌套鎖也是由加鎖者解鎖

  • 同一進程中的線程,如果枷鎖後沒有解鎖,任何其他線程都無法在獲得鎖,也就是常說的死鎖

  • 上鎖

    /* Lock a mutex.  */
    extern int pthread_mutex_lock (pthread_mutex_t *__mutex)
    	 __THROWNL __nonnull ((1));
    

    當一個線程執行到pthread_mutex_lock處時,如果該鎖此時被其他線程線程調用,那麼此線程會阻塞,一直等另外一個線程釋放鎖,然後嘗試請求鎖。

  • 解鎖

    /* Unlock a mutex.  */
    extern int pthread_mutex_unlock (pthread_mutex_t *__mutex)
    	 __THROWNL __nonnull ((1));
    

靜態鎖

  • 使用宏PTHREAD_MUTEX_INITIALIZER初始化

    pthread_mutex_t static_data_mutex = PTHREAD_MUTEX_INITIALIZER;
    
  • 靜態鎖初始化以後就可以直接使用,進行加鎖解鎖,和動態鎖類型,唯一不用的是,當調用pthread_mutex_trylock()時,如果正忙則返回EBUSY而不是掛起等待

鎖的銷燬

  • 銷燬鎖,意味着釋放它所佔用的所有資源,且要求鎖當前處於開發狀態
    	* Destroy a mutex.  */
    	extern int pthread_mutex_destroy (pthread_mutex_t *__mutex)
      	 __THROW __nonnull ((1));
    
  • 在Liunx中,互斥鎖不佔用任何資源,因此Linux Threads中的pthread_mutex_destroy()除了檢查鎖的狀態外沒有其他任何操作(忙就返回EBUSY

完整Demo

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

//自定義數據結構,用於測試
typedef struct ThreadData_t {
    pthread_t m_pid;
    char* m_threadName;
} ThreadData;

ThreadData threadData;
pthread_mutex_t thread_data_mutex;
pthread_mutex_t static_data_mutex = PTHREAD_MUTEX_INITIALIZER;

static void init_thread_mutex(void) {
    pthread_mutexattr_t mutex_attr;
    //PTHREAD_PROCESS_SHARED
    pthread_mutexattr_setpshared(&mutex_attr, PTHREAD_PROCESS_PRIVATE);
    pthread_mutexattr_settype(&mutex_attr,PTHREAD_MUTEX_DEFAULT);
    pthread_mutex_init(&thread_data_mutex, &mutex_attr); 
}

static void destory_thread_mutex(void) {
    pthread_mutex_destroy(&thread_data_mutex);
}
//線程函數routine
static void* test_thread1(void* thread_name) {
    fprintf(stderr, "%s try to lock!\n", (char*)thread_name);
    pthread_mutex_lock(&thread_data_mutex);
    threadData.m_pid = pthread_self();
    threadData.m_threadName = (char*)thread_name;
    fprintf(stderr, "%s mutex locked! \n", threadData.m_threadName);
    sleep(5);
    pthread_mutex_unlock(&thread_data_mutex);
    return NULL;
}

static void* test_thread2(void* thread_name) {
    fprintf(stderr, "%s try to lock!\n", (char*)thread_name);

    pthread_mutex_lock(&thread_data_mutex);
    threadData.m_pid = pthread_self();
    threadData.m_threadName = (char*)thread_name;
    fprintf(stderr, "%s mutex locked! \n", threadData.m_threadName);
    sleep(6);
    pthread_mutex_unlock(&thread_data_mutex);

    return NULL;
}
int main(int argc, char** argv) {
    pthread_t pid1, pid2;

    init_thread_mutex();

    if (pthread_create(&pid1, NULL, test_thread1, (void*)"test thread1") != 0) {
        fprintf(stderr, "create thread1 failed\n");
        return -1;
    }
    if (pthread_create(&pid2, NULL, test_thread2, (void*)"test thread2") != 0) {
        fprintf(stderr, "create thread2 failed\n");
        return -1;
    }
    pthread_join(pid1, NULL);
    pthread_join(pid2, NULL);

    destory_thread_mutex();
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章