三十九、Linux 執行緒——執行緒的同步和互斥
阿新 • • 發佈:2019-01-04
39.1 概念
- 執行緒同步
- 是一個巨集觀概念,在微觀上包含執行緒的相互排斥和執行緒先後執行的約束問題
- 解決同步方式
- 條件變數
- 執行緒訊號量
- 執行緒互斥
- 執行緒執行的相互排斥
- 解決互斥的方式
- 互斥鎖
- 讀寫鎖
- 執行緒訊號量
39.2 案例
atm_account.c
1 #include "atm_account.h" 2 3 /** 建立賬戶 */ 4 atm_Account *atm_account_Create(intcode, 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 [email protected] $< -lpthread clean: $(RM) mshell $(RM) $(SHARE_LIB) $(RM) $(OBJ_DIR)/$(OBJS)/*.o $(RM) $(SRC_DIR)/*.o
編譯執行結果: