linux程式和執行緒之間通訊方法和同步方法總結

readyao發表於2015-12-18

程式和執行緒之間的通訊方法

一:程式之間的通訊方法

1.訊息佇列
2.共享記憶體

3.管道:分為匿名管道用在父子程式之間通訊,命名管道用於父子程式或不相關程式之間通訊;

參考:linux程式間通訊-----管道總結例項

4.父子程式也可以通過檔案描述符通訊,共同開啟同一個檔案;

二:執行緒之間的通訊方法

1.全域性資料,全域性變數,全域性資料結構
2.建立執行緒的時候通過引數arg主執行緒傳遞資料給新執行緒 pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg);
新執行緒退出的時候通過void pthread_exit(void *retval);和int pthread_join(pthread_t thread, void **retval);向主執行緒傳遞資訊;
見部落格:多執行緒函式系列pthread_create(), pthread_join(), pthread_self(),pthread_exit(), pthread_detach()例項詳解

3.檔案控制程式碼,多個執行緒共享檔案

待續。。。這部分還要寫。。。


程式和執行緒之間的同步方法

1:訊號量

一般是0和1兩個值,進去臨界區減去1(P操作),離開臨界區加上1(V操作);如果涉及到對多個資源進行控制,那麼訊號量的值設定為資源的數目;

2:互斥量

互斥量其實是訊號量的一種;每當一個執行緒或程式訪問臨界區的時候就要先獲取互斥量,離開臨界區的時候釋放互斥量;如果獲取互斥量失敗,則阻塞;所以互斥量使多個執行緒或程式對臨界區的執行序列化;

見部落格:linux程式多執行緒互斥鎖的簡單使用

對互斥量進行操作的主要API

#include <pthread.h>
pthread_mutex_t fastmutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t recmutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
pthread_mutex_t errchkmutex = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP;

int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr);//初始化該互斥鎖
int pthread_mutex_lock(pthread_mutex_t *mutex);//請求佔用該互斥鎖
int pthread_mutex_trylock(pthread_mutex_t *mutex);//嘗試請求佔用該互斥鎖
int pthread_mutex_unlock(pthread_mutex_t *mutex);//釋放該互斥鎖
int pthread_mutex_destroy(pthread_mutex_t *mutex);//銷燬該互斥鎖

#include <pthread.h>
#include <time.h>
int pthread_mutex_timedlock(pthread_mutex_t *restrict mutex,const struct timespec *restrict abs_timeout);

對互斥量的屬性進行操作的主要API

#include <pthread.h>
int pthread_mutexattr_init(pthread_mutexattr_t *attr);
int pthread_mutexattr_destroy(pthread_mutexattr_t *attr);
int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int kind);
int pthread_mutexattr_gettype(const pthread_mutexattr_t *attr, int *kind);

int pthread_mutexattr_getpshared(const pthread_mutexattr_t *restrict attr, int *restrict pshared);
int pthread_mutexattr_setpshared(pthread_mutexattr_t *attr,int pshared);//設定互斥量的屬性;當pshared是PTHREAD_PROCESS_SHARED允許不同程式的執行緒使用互斥量;
//當pshared是PTHREAD_PROCESS_PRIVATE僅僅允許相同程式的執行緒使用互斥量;

2:讀-寫鎖

當多個執行緒對共享記憶體進行操作的時候就要控制它們了,否則很容易對共享記憶體的資料訪問發生競爭;
可以允許多個執行緒同時對共享記憶體進行讀取(因為它不改變共享記憶體的內容),它們可以擁有用於讀取的讀-寫鎖;但是任意時刻只允許一個執行緒對共享記憶體進行寫入或更改;
其實我們為了控制這種寫入的競爭發生,也可以使用互斥量來控制;但是有一個問題。。。如果使用互斥量的話,那麼每個時刻只能有一個執行緒對共享記憶體進行讀或寫;
但是我們想讓多個執行緒同時對共享記憶體進行讀取,這樣的話使用互斥量就有點效率低下了。這時我們應該使用讀-寫鎖;

備註:我們會發現對互斥量只有一個加鎖請求,但是對讀-寫鎖有兩個加鎖請求;

初始化/銷燬讀-寫鎖

#include <pthread.h>
int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);//銷燬讀-寫鎖
int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock, const pthread_rwlockattr_t *restrict attr);//初始化讀-寫鎖

請求佔有/嘗試請求讀鎖

#include <pthread.h>
int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);//請求獲得一個讀鎖,如果沒有其它執行緒持有寫鎖,則會得到讀鎖;但是有其它執行緒持有寫鎖,則該執行緒會阻塞;
int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);//請求獲得一個讀鎖,如果沒有其它執行緒持有寫鎖,則會得到讀鎖;但是有其它執行緒持///有寫鎖,則返回,不阻塞;

請求佔有/嘗試請求寫鎖

#include <pthread.h>
int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);//請求獲得一個寫鎖,如果有其它執行緒持有讀鎖或寫鎖,則返回,不阻塞;
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);//請求獲得一個寫鎖,只有在沒有其它執行緒持有讀鎖或寫鎖的情況下才會得到寫鎖,否則該執行緒會阻塞;

定時請求讀鎖

#include <pthread.h>
#include <time.h>
int pthread_rwlock_timedrdlock(pthread_rwlock_t *restrict rwlock,const struct timespec *restrict abs_timeout);//請求讀鎖,如果失敗會阻塞,但是隻會阻塞abs_timeout長時間

定時請求寫鎖

#include <pthread.h>
#include <time.h>
int pthread_rwlock_timedwrlock(pthread_rwlock_t *restrict rwlock,const struct timespec *restrict abs_timeout);//請求寫鎖,如果失敗會阻塞,但是隻會阻塞abs_timeout長時間

初始化/銷燬/設定/得到讀-寫鎖的屬性物件

#include <pthread.h>
int pthread_rwlockattr_destroy(pthread_rwlockattr_t *attr);//銷燬讀-寫鎖的屬性物件
int pthread_rwlockattr_init(pthread_rwlockattr_t *attr);//初始化讀-寫鎖的屬性物件

int pthread_rwlockattr_getpshared(const pthread_rwlockattr_t *restrict attr, int *restrict pshared);//得到屬性
int pthread_rwlockattr_setpshared(pthread_rwlockattr_t *attr,int pshared);//設定屬性;當pshared是PTHREAD_PROCESS_SHARED允許不同程式的執行緒使用讀-寫鎖;
//當pshared是PTHREAD_PROCESS_PRIVATE僅僅允許相同程式的執行緒使用讀-寫鎖;

3:條件變數

具體例項介紹見部落格:Linux多執行緒消費者和生產者模型例項(互斥鎖和條件變數使用)
條件變數和互斥量在一起使用;
比如當我們使用請求互斥量的時候,如果請求失敗會阻塞;
如果有情況是獲得了互斥鎖,但是條件不滿足,不能繼續執行,此時只能等待。。。。這個時候就要用到條件變數了。因為如果我們一直等待的話,那麼其它執行緒就不能獲得該鎖;此時有可能進入死鎖狀態;

解決辦法,此時應該呼叫pthread_cond_wait(&g_cond, &g_mutex),讓互斥鎖g_mutex在這個g_cond條件上等待;
執行緒呼叫pthread_cond_wait這個函式之後,核心會做下面這些事:
1,拿到鎖的執行緒,把鎖暫時釋放;
2,執行緒休眠,進行等待;
3,執行緒等待通知,要醒來。(重新獲取鎖)
執行緒庫將上面三步做成了原子性操作;和Linux核心繫結在一起;
其它執行緒在條件滿足的時候呼叫pthread_cond_signal(&g_cond);向這個條件變數g_cond上傳送一個訊號,表示條件滿足;
如果條件滿足,那麼剛才因為呼叫pthread_cond_wait而等待的執行緒會醒來(重新獲取鎖,再次判斷條件是否滿足);如果條件滿足,然後在臨界區進行操作,最後解鎖,離開臨界區;
//下面是man手冊對pthread_cond_wait的介紹:pthread_cond_wait atomically unlocks the mutex (as per pthread_unlock_mutex) and waits for the condition variable cond to be signaled. The thread execution  is  
suspended  and  does not consume any CPU time until the condition variable is signaled. The mutex must be locked by the calling thread on entrance to pthread_cond_wait.
Before returning to the calling thread, pthread_cond_wait re-acquires mutex (as per pthread_lock_mutex)

對條件變數操作的主要API

#include <pthread.h>
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;//條件變數靜態初始化
int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *cond_attr);//條件變數初始化
int pthread_cond_signal(pthread_cond_t *cond);//向這個條件變數g_cond上傳送一個訊號,表示條件滿足;
int pthread_cond_broadcast(pthread_cond_t *cond);//向這個條件變數g_cond上傳送一個訊號,表示條件滿足;
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);//讓互斥鎖g_mutex在這個g_cond條件上等待;
int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime);讓互斥鎖g_mutex在這個g_cond條件上等待abstime秒;
int pthread_cond_destroy(pthread_cond_t *cond);//銷燬條件變數

對條件變數屬性操作的主要API

#include <pthread.h>
int pthread_condattr_init(pthread_condattr_t *attr);//初始化條件變數屬性物件
int pthread_condattr_destroy(pthread_condattr_t *attr);//銷燬條件變數屬性物件
int pthread_condattr_getpshared(const pthread_condattr_t *restrict attr,int *restrict pshared);//獲得條件變數的屬性
int pthread_condattr_setpshared(pthread_condattr_t *attr, int pshared);//設定條件變數的屬性;當pshared是PTHREAD_PROCESS_SHARED允許不同程式的執行緒使用條件變數;
//當pshared是PTHREAD_PROCESS_PRIVATE僅僅允許相同程式的執行緒使用條件變數;

int pthread_condattr_getclock(const pthread_condattr_t *restrict attr, clockid_t *restrict clock_id);//得到屬性和超時服務時鐘clock_id,預設是系統時鐘
int pthread_condattr_setclock(pthread_condattr_t *attr, clockid_t clock_id);//設定屬性和超時服務時鐘clock_id,預設是系統時鐘

相關文章