三十九、Linux 线程——线程的同步和互斥

39.1 概念

  • 线程同步
    • 是一个宏观概念,在微观上包含线程的相互排斥和线程先后执行的约束问题
    • 解决同步方式
      • 条件变量
      • 线程信号量
  • 线程互斥
    • 线程执行的相互排斥
    • 解决互斥的方式
      • 互斥锁
      • 读写锁
      • 线程信号量

39.2 案例

  

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     return account;
15 }
16 
17 /** 销毁账户 */
18 void atm_account_Destroy(atm_Account *account)
19 {
20     if(NULL == account){
21         return ;
22     }
23 
24     free(account);
25 }
26 
27 /** 取款: 成功,则返回取款金额 */
28 double atm_account_Withdraw(atm_Account *account, double amt)
29 {
30     if(NULL == account) {
31         return 0.0;
32     }
33 
34     if(amt < 0 || amt > account->balance) {
35         return 0.0;
36     }
37 
38     double balance_tmp = account->balance;
39     sleep(1);
40     balance_tmp -= amt;
41     account->balance = balance_tmp;
42 
43     return amt;
44 }
45 
46 /** 存款: 返回存款的金额 */
47 double atm_account_Desposit(atm_Account *account, double amt)
48 {
49     if(NULL == account){
50         return 0.0;
51     }
52     if(amt < 0){
53         return 0.0;
54     }
55 
56     double balance_tmp = account->balance;
57     sleep(1);
58     balance_tmp += amt;
59     account->balance = balance_tmp;
60 
61     return amt;
62 }
63 
64 /** 查看账户余额 */
65 double atm_account_BalanceGet(atm_Account *account)
66 {
67     if(NULL == account){
68         return 0.0;
69     }
70 
71     double balance_tmp = account->balance;
72     return balance_tmp;
73 }

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 
11 /** 账户信息 */
12 typedef struct {
13     int         code;       ///< 银行账户的编码
14     double      balance;    ///< 账户余额
15 }atm_Account;
16 
17 /** 创建账户 */
18 extern atm_Account *atm_account_Create(int code, double balance);
19 /** 销毁账户 */
20 extern void atm_account_Destroy(atm_Account *account);
21 /** 取款 */
22 extern double atm_account_Withdraw(atm_Account *account, double amt);
23 /** 存款 */
24 extern double atm_account_Desposit(atm_Account *account, double amt);
25 /** 查看账户余额 */
26 extern double atm_account_BalanceGet(atm_Account *account);
27 
28 #endif

atm_handler.c

 1 #include "atm_handler.h"
 2 
 3 /** 定义取款操作的线程运行函数 */
 4 void *atm_handler_Withdraw(void *arg)
 5 {
 6     atm_handler_t *handler_tmp = (atm_handler_t *)arg;
 7     double amt = atm_account_Withdraw(handler_tmp->account, handler_tmp->amt);
 8 
 9     printf("%10s(0x%lu) withdraw %f from account %d\n", handler_tmp->name, pthread_self(), amt, handler_tmp->account->code);
10 
11    return (void *)0;
12 }
13 
14 /** 定义存款操作的线程运行函数 */
15 void *atm_handler_Desposit(void *arg)
16 {
17     atm_handler_t *handler_tmp = (atm_handler_t *)arg;
18     double amt = atm_account_Desposit(handler_tmp->account, handler_tmp->amt);
19 
20     printf("%10s(0x%lu) deposit %f from account %d\n", handler_tmp->name, pthread_self(), amt, handler_tmp->account->code);
21 
22    return (void *)0;
23 }
24 
25 /** 定义检查银行账户的线程运行函数 */
26 void *atm_handler_AccountCheck(void *arg)
27 {
28     return (void *)0;
29 }
30 
31 /** 账户操作主函数 */
32 atm_error_t atm_handler_main(void)
33 {
34     int err;
35     pthread_t boy, girl;
36     atm_Account *account = atm_account_Create(1000001, 10000);
37     if(NULL == account){
38         return ATM_ERROR_ACCOUNT_CREATE;
39     }
40 
41     atm_handler_t usr1, usr2;
42     strcpy(usr1.name, "boy");
43     usr1.account = account;
44     usr1.amt = 10000;
45 
46     strcpy(usr2.name, "girl");
47     usr2.account = account;
48     usr2.amt = 10000;
49 
50     /** 启动两个线程(boy 和 girl 线程)同时去操作同一个银行账户 */
51     if((err = pthread_create(&boy, NULL, atm_handler_Withdraw, (void *)&usr1)) != 0) {
52         perror("pthread create error");
53     }
54 
55     if((err = pthread_create(&girl, NULL, atm_handler_Withdraw, (void *)&usr2)) != 0) {
56         perror("pthread create error");
57     }
58     
59     /** 主线程阻塞 */
60     pthread_join(boy, NULL);
61     pthread_join(girl, NULL);
62 
63     printf("account balance: %f\n", atm_account_BalanceGet(account));
64     atm_account_Destroy(account);
65 
66     return ATM_ERROR_NONE;
67 }

atm_handler.h

 1 #ifndef __ATM_HANDLER_H__
 2 #define __ATM_HANDLER_H__
 3 
 4 #include "atm_account.h"
 5 #include <pthread.h>
 6 #include <stdio.h>
 7 #include <stdlib.h>
 8 #include <string.h>
 9 
10 typedef enum {
11     ATM_ERROR_NONE,
12     ATM_ERROR_ACCOUNT_CREATE
13 }atm_error_t;
14 
15 /** 账户操作结构体 */
16 typedef struct {
17     char            name[20];   ///< 操作人的姓名
18     atm_Account     *account;   ///< 操作的账户
19     double          amt;        ///< 操作的金额
20 }atm_handler_t;
21 
22 extern atm_error_t atm_handler_main(void);
23 
24 #endif

atm_test.c

1 #include "atm_handler.h"
2 
3 int main(void)
4 {
5     atm_handler_main();
6     return 0;
7 }

Makefile

#PROJECT_ROOT = $(dir $(abspath $(lastword $(MAKEFILE_LIST))))
PROJECT_ROOT = $(shell pwd)
SRC_DIR = $(PROJECT_ROOT)/src
INCLUDE_DIR = $(PROJECT_ROOT)/include
OBJ_DIR = $(PROJECT_ROOT)/obj
BIN_DIR = $(PROJECT_ROOT)/bin


# 找出 src 目录下的所有 .c 文件
C_SRCS = $(wildcard $(SRC_DIR)/*.c)
# 将所有的 src 下的 .c 文件替换为 .o 文件
C_OBJS = $(patsubst %c, %o, $(C_SRCS))
TARGET = test
SHARE_LIB = libatm.a

C_SRC_MAIN = atm_test.c

CC = gcc
CCFLAGS += fPIC
LDFLAGS += -shared -fPIC
ASFLAGS +=
ARFLAGS = -crs
LIBS_FLAGS = -L$(BIN_DIR)

RM = rm -rf
 
CFLAGS += -Wall -g -I$(INCLUDE_DIR)
INCDIR += -I$(INCLUDE_DIR)



.PHONY: all clean test

all: $(TARGET)
    cp $(SHARE_LIB) $(BIN_DIR)
    cp $(SRC_DIR)/*.o $(OBJ_DIR)/
    $(RM) $(SHARE_LIB) $(SRC_DIR)/*.o

$(TARGET): $(SHARE_LIB)
    $(CC) $(C_SRC_MAIN) -o $(TARGET) $(CFLAGS) $(INCDIR) $(LIBS_FLAGS) -latm -lpthread

$(SHARE_LIB): $(C_OBJS)
    $(AR) $(ARFLAGS) $(SHARE_LIB) $(C_OBJS)
    cp $(SHARE_LIB) $(BIN_DIR)

$(C_OBJS) : %.o:%.c
    $(CC) -c $(CFLAGS) $(INCDIR) -o $@ $< -lpthread

clean:
    $(RM) mshell 
    $(RM) $(SHARE_LIB) 
    $(RM) $(OBJ_DIR)/$(OBJS)/*.o 
    $(RM) $(SRC_DIR)/*.o

编译运行结果:

  

 

posted @ 2019-01-04 20:20  游戏进行中  阅读(295)  评论(0编辑  收藏  举报