40.1 互斥锁
40.1.1 介绍
- 互斥锁(mutex)是一种简单的加锁的方法来控制对共享资源的访问。
- 在同一时刻只能有一个线程掌握某个互斥锁,拥有上锁状态的线程能够对共享资源进行访问。
- 若其他线程希望上锁一个已经被上了互斥锁的资源,则该线程挂起,直到上锁的线程释放互斥锁为止。
- 互斥锁的数据类型
- pthread_mutex_t
4.1.2 互斥锁的创建和销毁
#include <pthread.h> int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutex_attr_t *mutexattr); int pthread_mutex_destroy(pthread_mutex_t *mutex);
- 函数参数:
- mutex:互斥锁
- mutexattr:互斥锁创建方式
- PTHREAD_MUTEX_INITALIZER:创建快速互斥锁
- PTHREAD_RECURSIVE_MUTEX_INITALIZER_NP:创建递归互斥锁
- PTHREAD_ERRORCHECK_MUTEX_INITALIZER_NP:创建检错互斥锁
- 返回值:成功,则返回 0,否则,返回错误编号
4.1.3 互斥锁上锁和解锁
1 #include <pthread.h> 2 /** 上锁,拿不到锁阻塞 */ 3 int pthread_mutex_lock(pthread_mutex_t *mutex); 4 /** 上锁,拿不到锁返回出错信息 */ 5 int pthread_mutex_trylock(pthread_mutex_t *mutex); 6 /** 释放锁 */ 7 int pthread_mutex_unlock(pthread_mutex_t *mutex);
- 函数参数:
- mutex:互斥锁
- 返回值:成功返回0,出错返回出错码
4.1.4 例子:
对前一个银行账户代码进行修改:
atm_account.h
1 #ifndef __ATM_ACCOUNT_H__ 2 #define __ATM_ACCOUNT_H__ 3 4 #include <math.h> 5 #include <malloc.h> 6 #include <stdlib.h> 7 #include <stdio.h> 8 #include <string.h> 9 #include <unistd.h> 10 #include <pthread.h> 11 12 /** 账户信息 */ 13 typedef struct { 14 int code; ///< 银行账户的编码 15 double balance; ///< 账户余额 16 17 pthread_mutex_t mutex; ///< 定义一把互斥锁,用来对多线程操作的银行账户(共享资源)进行加锁 18 }atm_Account; 19 20 /** 创建账户 */ 21 extern atm_Account *atm_account_Create(int code, double balance); 22 /** 销毁账户 */ 23 extern void atm_account_Destroy(atm_Account *account); 24 /** 取款 */ 25 extern double atm_account_Withdraw(atm_Account *account, double amt); 26 /** 存款 */ 27 extern double atm_account_Desposit(atm_Account *account, double amt); 28 /** 查看账户余额 */ 29 extern double atm_account_BalanceGet(atm_Account *account); 30 31 #endif
atm_account.c
1 #include "atm_account.h" 2 3 /** 创建账户 */ 4 atm_Account *atm_account_Create(int code, double balance) 5 { 6 atm_Account *account = (atm_Account *)malloc(sizeof(atm_Account)); 7 if(NULL == account) { 8 return NULL; 9 } 10 11 account->code = code; 12 account->balance = balance; 13 14 /** 对互斥锁进行初始化 */ 15 pthread_mutex_init(&account->mutex, NULL); 16 17 return account; 18 } 19 20 /** 销毁账户 */ 21 void atm_account_Destroy(atm_Account *account) 22 { 23 if(NULL == account){ 24 return ; 25 } 26 27 pthread_mutex_destroy(&account->mutex); 28 free(account); 29 } 30 31 /** 取款: 成功,则返回取款金额 */ 32 double atm_account_Withdraw(atm_Account *account, double amt) 33 { 34 if(NULL == account) { 35 return 0.0; 36 } 37 38 /** 对共享资源(账户进行加锁) */ 39 pthread_mutex_lock(&account->mutex); 40 41 if(amt < 0 || amt > account->balance) { 42 pthread_mutex_unlock(&account->mutex); 43 return 0.0; 44 } 45 46 double balance_tmp = account->balance; 47 sleep(1); 48 balance_tmp -= amt; 49 account->balance = balance_tmp; 50 51 pthread_mutex_unlock(&account->mutex); 52 53 return amt; 54 } 55 56 /** 存款: 返回存款的金额 */ 57 double atm_account_Desposit(atm_Account *account, double amt) 58 { 59 if(NULL == account){ 60 return 0.0; 61 } 62 63 /** 对共享资源(账户进行加锁) */ 64 pthread_mutex_lock(&account->mutex); 65 66 if(amt < 0){ 67 pthread_mutex_unlock(&account->mutex); 68 return 0.0; 69 } 70 71 double balance_tmp = account->balance; 72 sleep(1); 73 balance_tmp += amt; 74 account->balance = balance_tmp; 75 76 pthread_mutex_unlock(&account->mutex); 77 78 return amt; 79 } 80 81 /** 查看账户余额 */ 82 double atm_account_BalanceGet(atm_Account *account) 83 { 84 if(NULL == account){ 85 return 0.0; 86 } 87 88 /** 对共享资源(账户进行加锁) */ 89 pthread_mutex_lock(&account->mutex); 90 91 double balance_tmp = account->balance; 92 pthread_mutex_unlock(&account->mutex); 93 94 return balance_tmp; 95 }
编译运行结果如下:
不会发生同时取到 10000 的事情了。
40.2 互斥锁的类型和属性
40.2.1 互斥锁属性的创建和销毁
1 #include <pthread.h> 2 int pthread_mutexattr_init(pthread_mutexattr_t *attr); 3 int pthread_mutexattr_destroy(pthread_mutexattr_t *attr);
- 函数参数:
- attr:互斥锁属性
- 返回值:
- 成功返回0,出错返回错误编号
40.2.2 互斥锁进程共享属性操作---获得和设置
1 #include <pthread.h> 2 int pthread_mutexattr_getpshared(const pthread_mutexattr_t *restrict attr, int *restrict pshared); 3 int pthread_mutexattr_setpshared(const pthread_mutexattr_t *attr, int *pshared);
- 函数参数:
- attr:互斥锁属性
- pshared:进程共享属性
- PTHREAD_PROCESS_PRIVATE(默认情况)
- 锁只能用于一个进程内部的两个线程进行互斥
- PTHREAD_PROCESS_SHARED
- 锁可以用于两个不同进程中的线程进行互斥
- PTHREAD_PROCESS_PRIVATE(默认情况)
- 返回值:成功返回0,出错返回错误编号
40.2.3 互斥锁类型操作
1 #include <pthread.h> 2 int pthread_mutexattr_gettype(const pthread_mutexattr_t *restrict attr, int *restrict type); 3 int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type);
- 函数参数:
- attr:互斥锁属性
- type:互斥锁类型
- 标准互斥锁:PTHREAD_MUTEX_NORMAL
- 第一次上锁成功,第二次上锁会阻塞
- 递归互斥锁:PTHREAD_MUTEX_RECURSIVE
- 第一次上锁成功,第二次以后上锁还是成功,内部计数
- 检错互斥锁:PTHREAD_MUTEX_ERRORCHECK
- 第一次上锁成功,第二次上锁会出错
- 默认护持错:PTHREAD_MUTEX_DEFAULT(同标准互斥锁)
- 标准互斥锁:PTHREAD_MUTEX_NORMAL
- 返回值:
- 成功返回 0, 出错返回错误编号
40.2.4 例子
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <pthread.h> 4 #include <string.h> 5 6 7 int main(int argc, char *argv[]) 8 { 9 pthread_mutex_t mutex; 10 if(argc < 2){ 11 fprintf(stdout, "-usrage:%s [error | noraml | recursive\n]", argv[0]); 12 exit(1); 13 } 14 15 /** 定义互斥锁属性 */ 16 pthread_mutexattr_t mutexattr; 17 /** 初始化互斥锁属性 */ 18 pthread_mutexattr_init(&mutexattr); 19 20 if(!strcmp(argv[1], "error")){ 21 /** 设置互斥锁类型 */ 22 pthread_mutexattr_settype(&mutexattr, PTHREAD_MUTEX_ERRORCHECK); 23 } 24 else if(!strcmp(argv[1], "normal")){ 25 pthread_mutexattr_settype(&mutexattr, PTHREAD_MUTEX_NORMAL); 26 } 27 else if(!strcmp(argv[1], "recursive")){ 28 pthread_mutexattr_settype(&mutexattr, PTHREAD_MUTEX_RECURSIVE); 29 } 30 31 pthread_mutex_init(&mutex, &mutexattr); 32 if(pthread_mutex_lock(&mutex) != 0){ 33 printf("lock failure\n"); 34 } 35 else{ 36 printf("lock success\n"); 37 } 38 39 if(pthread_mutex_lock(&mutex) != 0){ 40 printf("lock failure\n"); 41 } 42 else{ 43 printf("lock success\n"); 44 } 45 46 pthread_mutex_unlock(&mutex); 47 pthread_mutex_unlock(&mutex); 48 49 pthread_mutexattr_destroy(&mutexattr); 50 pthread_mutex_destroy(&mutex); 51 52 return 0; 53 }