歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Unix知識 >> Unix基礎知識

UNIX環境高級編程:線程同步之互斥鎖、讀寫鎖和條件變量

一、使用互斥鎖

1、初始化互斥量

pthread_mutex_t mutex =PTHREAD_MUTEX_INITIALIZER;//靜態初始化互斥量  
int pthread_mutex_init(pthread_mutex_t*mutex,pthread_mutexattr_t*attr);//動態初始化互斥量  
int pthread_mutex_destory(pthread_mutex_t*mutex);//撤銷互斥量

不能拷貝互斥量變量,但可以拷貝指向互斥量的指針,這樣就可以使多個函數或線程共享互斥量來實現同步。上面動態申請的互斥量需要動態的撤銷。

2、加鎖和解鎖互斥量

int pthread_mutex_lock(pthread_mutex_t *mutex);  
int pthread_mutex_trylock(pthread_mutex_t *mutex);  
int pthread_mutex_unlock(pthread_mutex_t*mutex);

當調用pthread_mutex_lock加鎖互斥量時,如果此時互斥量已經被鎖住,則調用線程將被阻塞。而pthread_mutex_trylock函數當調用互斥量已經被鎖住時調用該函數將返回錯誤代碼EBUSY。使用和信號量一樣,先鎖住互斥量再處理共享數據,最後解鎖互斥量。

針對上信號量中的示例進行修改得:

#include<pthread.h>  
#include<stdio.h>  
#include<semaphore.h>  
#define NITERS 100000000  
/*共享變量*/
unsigned int cnt = 0;  
//sem_t mutex;  
pthread_mutex_t mutex;  
void *count(void *arg)  
{  
    int i;  
    for(i=0;i<NITERS;i++)  
    {  
        pthread_mutex_lock(&mutex);  
        cnt++;  
        pthread_mutex_unlock(&mutex);  
    }  
    return arg;  
}  
int main()  
{  
    pthread_t tid1,tid2;  
    int status;  
    pthread_mutex_init(&mutex,NULL);  
            
    pthread_mutex_destroy(&mutex);  
    if(cnt!=(unsigned)NITERS*2)  
        printf("Boom!,cnt=%d\n",cnt);  
    else
        printf("Ok cnt=%d\n",cnt);  
    return 0;  
}

3、使用多個互斥量

使用多個互斥量可能造成死鎖問題。如下:

線程1                                              線程2  
      
pthread_mutex_lock(&mutex_a);                     pthread_mutex_lock(&mutex_b);  
      
pthread_mutex_lock(&mutex_b);                     pthread_mutex_lock(&mutex_a);

當兩個線程都完成第一步時,都無法完成第二步,將造成死鎖。可以通過以下兩種方法來避免死鎖:

固定加鎖層次:所有需要同時加鎖互斥量A和互斥量B的代碼,必須先加鎖A再加鎖B。

試加鎖和回退:在鎖住第一個互斥量後,使用pthread_mutex_trylock來加鎖其他互斥量,如果失敗則將已加鎖的互斥量釋放,並重新加鎖。

查看本欄目更多精彩內容:http://www.bianceng.cn/OS/unix/

二、使用讀寫鎖

通過讀寫鎖,可以對受保護的共享資源進行並發讀取和獨占寫入。讀寫鎖是可以在讀取或寫入模式下鎖定的單一實體。要修改資源,線程必須首先獲取互斥寫鎖。必須釋放所有讀鎖之後,才允許使用互斥寫鎖。

1. 初始化和銷毀:

#include <pthread.h>  
int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock, const pthread_rwlockattr_t *restrict attr);  
int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);

同互斥量一樣, 在釋放讀寫鎖占用的內存之前, 需要先通過pthread_rwlock_destroy對讀寫鎖進行清理工作, 釋放由init分配的資源.

2.加鎖和解鎖

讀取讀寫鎖中的鎖 int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);  
讀取非阻塞讀寫鎖中的鎖 int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);  
寫入讀寫鎖中的鎖   int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);  
寫入非阻塞讀寫鎖中的鎖    int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);  
解除鎖定讀寫鎖 int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);

三、條件變量

假如某個線程需要等待系統處於某種狀態下才能繼續執行,Linux為了解決這種問題引入了條件變量這種線程同步對象,條件變量是用來通知共享數據狀態信息的,等待條件變量總是返回鎖住的互斥量,條件變量是與互斥量相關、也與互斥量保護的共享數據相關的信號機制。條件變量不提供互斥,需要一個互斥量來同步對共享數據的訪問,這就是為什麼在等待條件變量時必須指定一個互斥量。

1、創建和銷毀條件變量

#include <pthread.h>  
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;  
int pthread_cond_init(pthread_cond_t *restrict cond,const pthread_condattr_t *restrict attr);  
int pthread_cond_destroy(pthread_cond_t *cond);

2、等待條件變量

#include <pthread.h>  
int pthread_cond_timedwait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex,const struct timespec *restrict abstime);  
int pthread_cond_wait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex);

兩個函數的差別在於前者指定一個超時時間,在該時間內阻塞調用線程,並等待條件變量,如果規定時間內條件還沒有發生,則函數返回。每個條件變量必須一個特定互斥量關聯,當線程等待條件變量時,他必須將相關互斥量鎖住。在阻塞線程之前,條件變量等待操作將解鎖互斥量,而在重新返回線程之前,會在次鎖住互斥量。

3、喚醒條件變量等待線程

#include <pthread.h>  
int pthread_cond_broadcast(pthread_cond_t *cond);  
int pthread_cond_signal(pthread_cond_t *cond);

pthread_cond_signal將會激活等待線程中的一個;pthread_cond_broadcast將會激活所有的線程。另外請注意這兩個函數也需要互斥量來保護。

作者:csdn博客 ctthuangcheng

Copyright © Linux教程網 All Rights Reserved