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 }

  编译运行结果如下:

  四十、Linux 线程——互斥锁和读写锁

  不会发生同时取到 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
        • 锁可以用于两个不同进程中的线程进行互斥
  • 返回值:成功返回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(同标准互斥锁)
  • 返回值:
    • 成功返回 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 }
View Code

相关文章: