一、多線程的特點:並發和異步
同步是指一個事件一個事件的完成,只有完成了上面的事件才能開始下面的事件;異步是指一個調用或請求發給調用者,調用者不用等待結果的返回而繼續當前的處理。為了防止並發和異步帶來線程間資源的競爭的無序性,需要引入同步機制。同步機制有互斥量(互斥鎖)、讀寫鎖和條件變量。
二、臨界資源和臨界區
臨界資源指同一時間只允許一個線程訪問的資源
臨界區是指每個線程中訪問臨界資源的代碼
要使線程互斥的訪問資源,即應當讓它們互斥的進入臨界區。
三、
1.互斥鎖
工作流程:創建一個互斥鎖並初始化它,上鎖,解鎖,不用的時候銷毀它。
//定義一個互斥量 pthread_mutex_t mutex; //互斥鎖的初始化 //動態初始化 int pthread_mutex_init(pthread_mutex_t* restrict mutex,const pthread_mutexattr_t* restrict attr);//attr為屬性,NULL表示默認屬性 //靜態初始化 pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER; //上鎖 int pthread_mutex_lock(pthread_mutex_t* mutex);//如果其它線程已經把互斥鎖上鎖,則這里阻塞線程
int pthread_mutex_trylock(pthread_mutex_t* mutex);//嘗試上鎖,若已經上鎖了,不阻塞,立即返回EBUSY //解鎖 int pthread_mutex_unlock(pthread_mutex_t* mutex); //互斥鎖的銷毀 int pthread_mutex_destroy(pthread_mutex_t* mutex);
2.讀寫鎖
比互斥鎖具有更高的並行性,但速度未必比互斥鎖快,因為讀寫鎖開銷更大。以讀模式加鎖后仍可以以讀模式加鎖,並不會造成阻塞。讀的時候,只要有寫的線程來了,后面再來的讀線程也會被阻塞,防止寫線程一直等。
//創建並初始化 pthread_rwlock_t rwlock=PTHREAD_RWLOCK_INITIALIZER; //動態初始化 int pthread_rwlock_init(pthread_rwlock_t* restric rwlock,const pthread_rwlock_t* restrict attr); //上鎖 //讀鎖 int pthread_rwlock_rdlock(pthread_rwlock_t* rwlock); int pthread_rwlock_trylock(pthread_rwlock_t* rwlock);//不阻塞,立即返回EBUSY //寫鎖 int pthread_rwlock_wrlock(pthread_rwlock_t* rwlock); int pthread_rwlock_trywrlock(pthread_rwlock_t* rwlock); //解鎖,無需說明是讀鎖還是寫鎖 int pthread_rwlock_unlock(pthread_rwlock_t* rwlock); //讀寫鎖銷毀 int pthread_rwlock_destroy(pthread_rwlock_t* rwlock);
3.條件變量
條件變量一般結合互斥鎖來使用
//創建條件變量並初始化 pthread_cond_t cond=PTHREAD_COND_INITIALIZER; //動態初始化 int pthread_cond_init(pthread_cond_t * cond,pthread_condattr_t* cond_attr);//cond_attr為屬性,NULL表示默認屬性 //等待條件變量 int thread_cond_wait(pthread_cond_t * restrict cond,pthread_cond_t * restrict mutex);//調用之前應當先把互斥量上鎖,然后該函數解開鎖,然后阻塞等待條件成立,由下面的函數喚醒,並鎖上互斥量 //喚醒等待條件變量的線程 int pthread_cond_signal(pthread_cond_t* cond);//只喚醒一個等待條件變量的線程 int pthread_cond_broadcast(pthread_cond_t* cond);//喚醒所有等待線程 //條件變量的銷毀 int pthread_cond_destroy(pthread_cond_t* cond);