1. 程式人生 > >1執行緒同步:互斥量,死鎖

1執行緒同步:互斥量,死鎖



1執行緒為什麼要同步

A:共享資源,多個執行緒都可對共享資源操作。

B:執行緒操作共享資源的先後順序不確定。

C:處理器對儲存器的操作一般不是原子操作。

2互斥量

mutex操作原語

pthread_mutex_t

pthread_mutex_init

pthread_mutex_destroy

pthread_mutex_lock

pthread_mutex_trylock

pthread_mutex_unlock

3臨界區(Critical Section

保證在某一時刻只有一個執行緒能訪問資料的簡便辦法。在任意時刻只允許一個執行緒對共享資源進行訪問。如果有多個執行緒試圖同時訪問臨界區,那麼在有一個執行緒進入後其他所有試圖訪問此臨界區的執行緒將被掛起,並一直持續到進入臨界區的執行緒離開。臨界區在被釋

放後,其他執行緒可以繼續搶佔,並以此達到用原子方式操作共享資源的目的。

4臨界區的選定

臨界區的選定應儘可能小,如果選定太大會影響程式的並行處理效能。

5互斥量例項

依賴的標頭檔案

#include<pthread.h>

函式宣告

int pthread_mutex_destroy(pthread_mutex_t*mutex);

名稱:

pthread_mutex_destroy

功能:

釋放對互斥變數分配的資源

標頭檔案:

#include <pthread.h>

函式原形:

int  pthread_mutex_destroy(pthread_mutex_t *mutex);

引數:

返回值:

若成功則返回0,否則返回錯誤編號。

int pthread_mutex_init(pthread_mutex_t*restrict mutex, const pthread_mutexattr_t *restrict attr);

名稱:

pthread_mutexattr_init

功能:

初始化互斥鎖。

標頭檔案:

#include <pthread.h>

函式原形:

int pthread_mutex_init(pthread_mutex_t * mutex,

const pthread_mutex_t *attr);

引數:

mutex 互斥量

attr    互斥鎖屬性

返回值:

若成功則返回0,否則返回錯誤編號。

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/ pthread_mutex_unlock

功能:

對互斥量加/減鎖

標頭檔案:

#include <pthread.h>

函式原形:

int pthread_mutex_lock(pthread_mutex_t *mutex);

int pthread_mutex_trylock(pthread_mutex_t *mutex);

int pthread_mutex_unlock(pthread_mutex_t *mutex);

引數:

返回值:

若成功則返回0,否則返回錯誤編號。

函式說明:

對互斥量進行加鎖,需要呼叫pthread_mutex_lock,如果互斥量已經上鎖,呼叫執行緒阻塞直至互斥量解鎖。對互斥量解鎖,需要呼叫pthread_mutex_unlock.

如果執行緒不希望被阻塞,他可以使用pthread_mutex_trylock嘗試對互斥量進行加鎖。如果呼叫pthread_mutex_trylock時互斥量處於未鎖住狀態,那麼pthread_mutex_trylock將鎖住互斥量,否則就會失敗,不能鎖住互斥量,而返回EBUSY

6互斥鎖建立

有兩種方法建立互斥鎖,靜態方式和動態方式。

APOSIX定義了一個巨集PTHREAD_MUTEX_INITIALIZER來靜態初始化互斥鎖,方法如下:

pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER;

B:動態方式是採用pthread_mutex_init()函式來初始化互斥鎖,API定義如下:

int pthread_mutex_init(pthread_mutex_t *mutex, constpthread_mutexattr_t *mutexattr);

其中mutexattr用於指定互斥鎖屬性,如果為NULL則使用預設屬性。

C:pthread_mutex_destroy ()用於登出一個互斥鎖,API定義如下:

intpthread_mutex_destroy(pthread_mutex_t *mutex);

D:pthread_mutex_lock()加鎖

E:pthread_mutex_unlock()解鎖

F:pthread_mutex_trylock()測試加鎖

G:釋放記憶體前需要呼叫pthread_mutex_destory.

案例說明互斥量加鎖的必要性:

#include<stdio.h>

#include<pthread.h>

#include<stdlib.h>

#include<unistd.h>

void *thread_function(void *arg);

/*run_now代表共享資源*/

int run_now = 1;

int main(void)

{

int print_count1 = 0;/*用於迴圈控制*/

pthread_t a_thread;

/*建立一個程序*/

if(pthread_create(&a_thread,NULL,thread_function,NULL)){

perror("Thread creation failed!");

exit(1);

}

while(print_count1++ < 5){

/*主執行緒:如果run_now1就把它修改為2*/

if(run_now == 1) {

printf("main thread is run\n");

run_now = 2;

} else {

printf("main thread is sleep\n");

sleep(1);

}

}

//等待子執行緒結束

pthread_join(a_thread,NULL);

exit(0);

}

void *thread_function(void *arg) {

int print_count2 = 0;

while(print_count2++ < 5){

if(run_now == 2) /*子執行緒:如果run_now1就把它修改為1*/

{

printf("function thread is run\n");

run_now = 1;

}

else

{

printf("function thread is sleep\n");

sleep(1);

}

}

pthread_exit(NULL);

}

執行結果:

現象:main執行緒和function執行緒是交替執行的。它們都可以對run_now進行操作。

加鎖後的程式碼

#include <stdio.h>

#include <pthread.h>

#include <stdio.h>

#include <stdlib.h>

void *thread_function(void *arg);

int run_now=1;/*run_now代表共享資源*/

pthread_mutex_t work_mutex;/*定義互斥量*/

int main(void) {

int res;

int print_count1=0;

pthread_t a_thread;

if(pthread_mutex_init(&work_mutex,NULL)!=0)/*初始化互斥量*/

{

perror("Mutex init faied");

exit(1);

}

if(pthread_create(&a_thread,NULL,thread_function,NULL)!=0)/*建立新執行緒*/

{

perror("Thread createion failed");

exit(1);

}

if(pthread_mutex_lock(&work_mutex)!=0)/*對互斥量加鎖*/

{

perror("Lock failed");

exit(1);

} else {

printf("main lock\n");

}

while(print_count1++<5) {

if(run_now == 1)/*主執行緒:如果run_now1就把它修改為2*/

{

printf("main thread is run\n");

run_now=2;

} else {

printf("main thread is sleep\n");

sleep(1);

}

}

if(pthread_mutex_unlock(&work_mutex)!=0) /*對互斥量解鎖*/

{

perror("unlock failed");

exit(1);

} else {

printf("main unlock\n");

}

pthread_mutex_destroy(&work_mutex); /*收回互斥量資源*/

pthread_join(a_thread,NULL); /*等待子執行緒結束*/

exit(0);

}

void *thread_function(void *arg) {

int print_count2=0;

sleep(1);

if(pthread_mutex_lock(&work_mutex)!=0) {

perror("Lock failed");

exit(1);

} else {

printf("function lock\n");

}

while(print_count2++<5) {

if(run_now==2)/*分程序:如果run_now1就把它修改為1*/

{

printf("function thread is run\n");

run_now=1;

} else {

printf("function thread is sleep\n");

sleep(1);

}

}

if(pthread_mutex_unlock(&work_mutex)!=0)/*對互斥量解鎖*/

{

perror("unlock failed");

exit(1);

} else {

printf("function unlock\n");

}

pthread_exit(NULL);

}

執行結果如下:

總結:從執行結果可以看到,當主程序把互斥量鎖住後,子程序就不能對共享資源進行操作了,只能是同步的操作了。

#include<stdio.h>

#include<stdlib.h>

#include<pthread.h>

#define NLOOP 5000

int counter;

pthread_mutex_t counter_mutex = PTHREAD_MUTEX_INITIALIZER;

void *doit(void *);

int main(int argc,char **argv){

pthread_t tidA,tidB;

pthread_create(&tidA,NULL,doit,NULL);

pthread_create(&tidB,NULL,doit,NULL);

/*wait for both thread to terminate*/

pthread_join(tidA,NULL);

pthread_join(tidB,NULL);

return 0;

}

void *doit(void *vptr){

int i,val;

for(i = 0;i < NLOOP;i++) {

pthread_mutex_lock(&counter_mutex);

val = counter;

printf("%x:%d\n",(unsigned int) pthread_self(),val + 1);

counter = val + 1;

pthread_mutex_unlock(&counter_mutex);

}

return NULL;

}

執行結果:

  1. 死鎖

    A同一個執行緒在擁有A鎖的情況下再次請求獲得A

    B執行緒一擁有A鎖,請求獲得B鎖;執行緒二擁有B鎖,請求獲得A鎖,出現死鎖,最終導致的結果是互相等待。