Linux執行緒淺析[執行緒的同步和互斥之執行緒互斥鎖]
Linux執行緒淺析[執行緒的同步和互斥]
- 執行緒同步
- 執行緒互斥
- 執行緒互斥的相關函式
- 執行緒同步的相關函式
執行緒同步
是巨集觀上的一個概念,在微觀上面包含執行緒的相互排斥和執行緒的執行順序的約束問題
解決方法:
條件變數
執行緒訊號量
例子:一棟大樓的建造,包含了質監局的檢驗和工程隊的施工,那麼假設質監局和工程隊是兩個執行緒,而大樓則為共享資源,首先相互排斥的原則為工程隊施工的時候,質監局是不能進行檢驗的,因為這個時候大樓還沒有建好,而質監局的檢驗依賴於工程隊施工的結果,所以質監局必須等待工程隊將大樓建造好.所以後一個執行緒依賴於前一個執行緒對共享資源操作的結果.所以說執行緒同步是包含了相互排斥和執行緒的執行順序.
執行緒互斥
執行緒的相互排斥
解決方法:
互斥鎖
讀寫鎖
執行緒訊號量
例子:
一個公用廁所,假設只有一個坑,那麼很多人去上廁所的時候,後一個就必須等後一個上完廁所之後才能上廁所.所以同一時間只能有一個人上廁所.這就是互斥.其實在生活中有很多例子.如銀行賬戶的操作問題.12306的售票問題等.都是互斥
注意:同步包含了互斥,互斥僅僅只是相互排斥,而同步是互斥加順序
先來一段有問題的程式碼:兩個執行緒同時去訪問同一個賬戶的問題:
account.h
/*
* ===========================================================================
*
* Filename: account.h
* Description:
* Version: 1.0
* Created: 2017年03月28日 22時04分18秒
* Revision: none
* Compiler: gcc
* Author: (),
* Company:
*
* ===========================================================================
*/
#ifndef __ACCOUNT_H_
#define __ACCOUNT_H_
//宣告銀行賬戶的結構體
typedef struct{
int code;
double balance;
}Account;
//建立銀行賬戶
extern Account* create_account(int code,double balance);
//銷燬一個賬戶
extern void destory_account(Account* account);
//存款
extern double withdraw(Account* account,double amt);
//取款
extern double deposit(Account* a,double amt);
//檢視賬戶餘額
extern double get_balance(Account* account);
#endif
account.c
/*
* ===========================================================================
*
* Filename: account.c
* Description:
* Version: 1.0
* Created: 2017年03月30日 21時16分28秒
* Revision: none
* Compiler: gcc
* Author: (),
* Company:
*
* ===========================================================================
*/
#include"account.h"
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<malloc.h>
#include<assert.h>
#include<pthread.h>
/*
*建立一個賬戶
*返回這個賬戶的指標
*
* */
extern Account* create_account(int code,double balance){
Account* account = (Account*)malloc(sizeof(Account));
assert(account !=NULL);
account->code = code;
account->balance = balance;
//初始化鎖的過程
return account;
}
/* *
*銷燬一個賬戶
* */
extern void destory_account(Account* account){
assert(account!=NULL);
free(account);
}
/* *
*取款,返回的是賬戶的餘額
*
* */
extern double withdraw(Account * account,double amt){
assert(account != NULL);
if(amt < 0 || amt > account->balance){
return 0.0;
}
int balance = account -> balance;
sleep(1);
int result = balance - amt;
account ->balance = result;
//pthread_mutex_unlock(&account->pthreadmutex);
return amt;
}
/* *
*存款,返回的也是賬戶的餘額
*
* */
extern double deposit(Account* account,double amt){
assert(account != NULL);
if(amt < 0){
return 0.0;
}
int result = account ->balance + amt;
sleep(2);
account->balance = result;
return result;
}
/* *
*獲取的就是這個賬戶的餘額
*
* */
extern double get_balance(Account* account){
assert(account !=NULL);
return account -> balance;
}
accountTest.c
/*
* ===========================================================================
*
* Filename: accountTest.c
* Description:
* Version: 1.0
* Created: 2017年03月30日 21時31分19秒
* Revision: none
* Compiler: gcc
* Author: (),
* Company:
*
* ===========================================================================
*/
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<pthread.h>
#include"account.h"
typedef struct{
char name[20];
Account* account;
double amt;
}ArgvType;
/* *
*檢查賬戶的函式
* */
void* th_check(void *argv){
ArgvType* argvType = (void*)argv;
double balance = get_balance(argvType->account);
printf("name:%s,balance:%f,pthread:%lx\n",argvType->name,balance,pthread_self());
return (void*)0;
}
/* *
*取款函式
* */
void* th_withdraw(void *argv){
ArgvType* argvType = (ArgvType*)argv;
double balance = withdraw(argvType->account,argvType->amt);
printf("name:%s,balance:%f,pthread:%lx\n",argvType->name,balance,pthread_self());
return (void*)0;
}
/* *
*存款函式
* */
void* th_deposite(void *argv){
ArgvType* argvType = (ArgvType*)argv;
double balance = deposit(argvType->account,argvType->amt);
printf("name:%s,balance:%f,pthread:%lx\n",argvType->name,balance,pthread_self());
return (void*)0;
}
int main(int argc,char *argv[]){
int result;
pthread_t boyfriend,girlfriend;
Account *account = create_account(10001,10000);
ArgvType argv_typeboy,argv_typegirl;
strcpy(argv_typeboy.name,"zhangsan");
strcpy(argv_typegirl.name,"xiaoli");
argv_typeboy.account = account;
argv_typegirl.account = account;
argv_typeboy.amt = 10000;
argv_typegirl.amt = 10000;
if((result = pthread_create(&boyfriend,NULL,th_withdraw,(void*)&argv_typeboy))!=0){
perror("boythread create error");
exit(EXIT_FAILURE);
}
if((result = pthread_create(&girlfriend,NULL,th_withdraw,(void*)&argv_typegirl))!=0){
perror("girlthread create error");
exit(EXIT_FAILURE);
}
pthread_join(boyfriend,NULL);
pthread_join(girlfriend,NULL);
printf("get_balance:%f\n",get_balance(account));
printf("thread:%lx exe ended\n",pthread_self());
return 0;
}
name:zhangsan,withdraw:10000.000000,balance:0.000000,pthread:7f34bf2a9700
name:xiaoli,withdraw:10000.000000,balance:0.000000,pthread:7f34beaa8700
get_balance:0.000000
thread:7f34bfa94740 exe ended
輸出的結果如下所示:
從上面輸出結果中我們可以看到,其實xiaoli和zhangsan都取到了10000,但是這中情況是及其不符合日常生活的邏輯的,而我們的執行緒互斥的目的也就是為了解決這樣一種併發,即多個執行緒訪問同一個共享資源的時候,怎麼去進行處理,後面在此例子基礎上面去做修改.
執行緒互斥的相關函式
互斥鎖:
互斥鎖是一種簡單的加鎖的方法來控制對共享資源的訪問。在同一時刻只能有一個執行緒掌握某個互斥鎖,擁有上鎖狀態的執行緒能夠對共享資源的訪問,若其他執行緒希望上鎖一個已經被上了鎖的資源,則該執行緒掛起,知道上鎖的執行緒釋放互斥鎖為止;
互斥鎖資料型別:pthread_mutex_t
#include<pthread.h>
int pthread_mutex_init(pthread_mutex_t *restrict mutex,const pthread_mutexattr_t *mutexattr);//初始化互斥鎖
int pthread_mutex_destory(pthread_mutex_t * mutex);
//銷燬互斥鎖
返回:成功返回0,失敗返回錯誤編號
引數:
mutex:互斥鎖
mutexattr:互斥鎖建立方式
PTHREAD_MUTEX_INITIALIZER:建立快速互斥鎖
PTHREAD_RECERSIVE_MUTEX_INITIALIZER_NP:建立遞迴互斥鎖
PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP:建立檢錯互斥鎖
互斥鎖的加鎖和釋放鎖的過程
#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,錯誤返回錯誤碼
引數:mutex
一個共享資源繫結一把鎖,
建議:定義在結構體中,儘量不設定成為全域性變數,否則可能會出現一把鎖去鎖幾百個賬戶,導致併發性的下降:
臨界區:對共享資源進行加鎖到釋放鎖的整個程式碼區域(從上鎖開始到釋放鎖結束)
互斥鎖的屬性建立和銷燬;
#include<pthread.h>
int pthread_mutexattr_init(pthread_mutexattr_t *attr);
int pthread_mutexattr_destory(pthead_muteattr_t *attr);
返回值:成功返回0,失敗返回錯誤碼
引數:
attr:互斥鎖屬性
互斥鎖的程序共享屬性:
#include<pthread.h>
int pthread_mutexattr_getpshared(const pthread_mutexattr_t *restrict attr,int *restrict pshared)
int pthread_mutexattr_setpshared(pthread_mutexattr_t *attr,int pshared)
返回:成功返回0,失敗返回錯誤編號
引數:
attr:互斥鎖屬性
pshared:程序共享屬性
PTHREAD_PROCESS_PRIVATE(預設)
鎖只能用於一個程序內部的兩個執行緒進行互斥
PTHREAD_PROCESS_SHARED
鎖能夠用於兩個不同程序中的執行緒進行互斥(跨程序)
一般情況下我們都是在同一個程序中去使用互斥鎖
互斥鎖的型別:
#include<pthread.h>
int pthread_mutexattr_gettype(const pthread_mutexattr_t *restrict attr,int *restrict type)
int pthread_mutexattr_settype(pthread_amutexattr_t *attr,int type)
引數
attr 互斥鎖屬性
type:互斥鎖型別
標準互斥鎖:PTHREAD_MUTEX_NOMAL
第一次上鎖成功,第二次上鎖失敗
遞迴互斥鎖:PTHREAD_MUTEX_RECURSIVE
第一次上鎖成功,第二次上鎖還是成功,內部計數
檢錯互斥鎖:PTHREAD_MUTEX_ERRORCHECK
第一次上鎖成功,第二次上錯會出錯
預設互斥鎖:PTHREAD_MUTEX_DEFAULT(同標準互斥鎖)
先上一個簡單的上鎖的案例:,在上述基礎上修改的
/*
* ===========================================================================
*
* Filename: account.h
* Description:
* Version: 1.0
* Created: 2017年03月28日 22時04分18秒
* Revision: none
* Compiler: gcc
* Author: (),
* Company:
*
* ===========================================================================
*/
#ifndef __ACCOUNT_H_
#define __ACCOUNT_H_
//宣告銀行賬戶的結構體
//引用pthread標頭檔案.方便後面加鎖
#include<pthread.h>
typedef struct{
int code;
double balance;
//將鎖宣告在結構體中,有助於每一個這樣的結構體都有一把鎖,那麼在操作的時候,有利於優化併發效果
pthread_mutex_t pthreadmutex;
}Account;
//建立銀行賬戶
extern Account* create_account(int code,double balance);
//銷燬一個賬戶
extern void destory_account(Account* account);
//存款
extern double withdraw(Account* account,double amt);
//取款
extern double deposit(Account* a,double amt);
//檢視賬戶餘額
extern double get_balance(Account* account);
#endif
/*
* ===========================================================================
*
* Filename: account.c
* Description:
* Version: 1.0
* Created: 2017年03月30日 21時16分28秒
* Revision: none
* Compiler: gcc
* Author: (),
* Company:
*
* ===========================================================================
*/
#include"account.h"
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<malloc.h>
#include<assert.h>
#include<pthread.h>
/*
*建立一個賬戶
*返回這個賬戶的指標
*
* */
extern Account* create_account(int code,double balance){
Account* account = (Account*)malloc(sizeof(Account));
assert(account !=NULL);
account->code = code;
account->balance = balance;
//初始化鎖的過程
pthread_mutex_init(&account->pthreadmutex,NULL);
return account;
}
/* *
*銷燬一個賬戶
* */
extern void destory_account(Account* account){
assert(account!=NULL);
free(account);
//銷燬鎖的過程
pthread_mutex_destroy(&account->pthreadmutex);
}
/* *
*取款,返回的是賬戶的餘額
*
* */
extern double withdraw(Account * account,double amt){
assert(account != NULL);
//上鎖的過程
pthread_mutex_lock(&account->pthreadmutex);
if(amt < 0 || amt > account->balance){
//解鎖的過程
pthread_mutex_unlock(&account->pthreadmutex);
return 0.0;
}
int balance = account -> balance;
sleep(1);
int result = balance - amt;
account ->balance = result;
//解鎖的過程
pthread_mutex_unlock(&account->pthreadmutex);
return amt;
}
/* *
*存款,返回的也是賬戶的餘額
*
* */
extern double deposit(Account* account,double amt){
assert(account != NULL);
//上鎖的過程
pthread_mutex_lock(&account->pthreadmutex);
if(amt < 0){
//解鎖的過程
pthread_mutex_unlock(&account->pthreadmutex);
return 0.0;
}
int balance = account ->balance;
sleep(2);
int result = balance + amt;
account->balance = result;
//解鎖的過程
pthread_mutex_unlock(&account->pthreadmutex);
return result;
}
/* *
*獲取的就是這個賬戶的餘額
*
* */
extern double get_balance(Account* account){
assert(account !=NULL);
return account -> balance;
}
/*
* ===========================================================================
*
* Filename: accountTest.c
* Description:
* Version: 1.0
* Created: 2017年03月30日 21時31分19秒
* Revision: none
* Compiler: gcc
* Author: (),
* Company:
*
* ===========================================================================
*/
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<pthread.h>
#include"account.h"
typedef struct{
char name[20];
Account* account;
double amt;
}ArgvType;
/* *
*檢查賬戶的函式
* */
void* th_check(void *argv){
ArgvType* argvType = (void*)argv;
double balance = get_balance(argvType->account);
printf("name:%s,balance:%f,pthread:%lx\n",argvType->name,balance,pthread_self());
return (void*)0;
}
/* *
*取款函式
* */
void* th_withdraw(void *argv){
ArgvType* argvType = (ArgvType*)argv;
double balance = withdraw(argvType->account,argvType->amt);
printf("name:%s,balance:%f,pthread:%lx\n",argvType->name,balance,pthread_self());
return (void*)0;
}
/* *
*存款函式
* */
void* th_deposite(void *argv){
ArgvType* argvType = (ArgvType*)argv;
double balance = deposit(argvType->account,argvType->amt);
printf("name:%s,balance:%f,pthread:%lx\n",argvType->name,balance,pthread_self());
return (void*)0;
}
int main(int argc,char *argv[]){
int result;
pthread_t boyfriend,girlfriend;
Account *account = create_account(10001,10000);
ArgvType argv_typeboy,argv_typegirl;
strcpy(argv_typeboy.name,"zhangsan");
strcpy(argv_typegirl.name,"xiaoli");
argv_typeboy.account = account;
argv_typegirl.account = account;
argv_typeboy.amt = 10000;
argv_typegirl.amt = 10000;
if((result = pthread_create(&boyfriend,NULL,th_withdraw,(void*)&argv_typeboy))!=0){
perror("boythread create error");
exit(EXIT_FAILURE);
}
if((result = pthread_create(&girlfriend,NULL,th_withdraw,(void*)&argv_typegirl))!=0){
perror("girlthread create error");
exit(EXIT_FAILURE);
}
pthread_join(boyfriend,NULL);
pthread_join(girlfriend,NULL);
printf("get_balance:%f\n",get_balance(account));
printf("thread:%lx exe ended\n",pthread_self());
return 0;
}
輸出的結果如上所示,這個時候其實取款的時候就已經沒有併發情況再出現了
/*
* ===========================================================================
*
* Filename: account.c
* Description:
* Version: 1.0
* Created: 2017年03月30日 21時16分28秒
* Revision: none
* Compiler: gcc
* Author: (),
* Company:
*
* ===========================================================================
*/
#include"account.h"
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<malloc.h>
#include<assert.h>
#include<pthread.h>
static pthread_mutexattr_t attr;
/*
*建立一個賬戶
*返回這個賬戶的指標
*
* */
extern Account* create_account(int code,double balance){
Account* account = (Account*)malloc(sizeof(Account));
assert(account !=NULL);
account->code = code;
account->balance = balance;
//初始化鎖的過程
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr,PTHREAD_MUTEX_NORMAL);
//pthread_mutexattr_settype(&attr,PTHREAD_MUTEX_RECURSIVE);
//pthread_mutexattr_settype(&attr,PTHREAD_MUTEX_ERRORCHECK);
//pthread_mutex_init(&account->pthreadmutex,NULL);
pthread_mutex_init(&account->pthreadmutex,&attr);
return account;
}
/* *
*銷燬一個賬戶
* */
extern void destory_account(Account* account){
assert(account!=NULL);
free(account);
//銷燬鎖的過程
pthread_mutexattr_destroy(&attr);
pthread_mutex_destroy(&account->pthreadmutex);
}
/* *
*取款,返回的是賬戶的餘額
*
* */
extern double withdraw(Account * account,double amt){
assert(account != NULL);
//上鎖的過程
pthread_mutex_lock(&account->pthreadmutex);
if(amt < 0 || amt > account->balance){
//解鎖的過程
pthread_mutex_unlock(&account->pthreadmutex);
return 0.0;
}
int balance = account -> balance;
sleep(1);
int result = balance - amt;
account ->balance = result;
//解鎖的過程
pthread_mutex_unlock(&account->pthreadmutex);
return amt;
}
/* *
*存款,返回的也是賬戶的餘額
*
* */
extern double deposit(Account* account,double amt){
assert(account != NULL);
//上鎖的過程
pthread_mutex_lock(&account->pthreadmutex);
if(amt < 0){
//解鎖的過程
pthread_mutex_unlock(&account->pthreadmutex);
return 0.0;
}
int balance = account ->balance;
sleep(2);
int result = balance + amt;
account->balance = result;
//解鎖的過程
pthread_mutex_unlock(&account->pthreadmutex);
return result;
}
/* *
*獲取的就是這個賬戶的餘額
*
* */
extern double get_balance(Account* account){
assert(account !=NULL);
return account -> balance;
}
以上都是對c的pthread互斥鎖做的一個相對比較簡單的一些使用方法.有興趣的可以copy下來run一下,因為我也是新手,寫的不好的地方歡迎指出