三十九、Linux 线程——线程的同步和互斥
39.1 概念
- 线程同步
- 是一个宏观概念,在微观上包含线程的相互排斥和线程先后执行的约束问题
- 解决同步方式
- 条件变量
- 线程信号量
- 线程互斥
- 线程执行的相互排斥
- 解决互斥的方式
- 互斥锁
- 读写锁
- 线程信号量
39.2 案例


atm_account.c
#include "atm_account.h" /** 创建账户 */
atm_Account *atm_account_Create(int code, double balance)
{
atm_Account *account = (atm_Account *)malloc(sizeof(atm_Account));
if(NULL == account) {
return NULL;
} account->code = code;
account->balance = balance; return account;
} /** 销毁账户 */
void atm_account_Destroy(atm_Account *account)
{
if(NULL == account){
return ;
} free(account);
} /** 取款: 成功,则返回取款金额 */
double atm_account_Withdraw(atm_Account *account, double amt)
{
if(NULL == account) {
return 0.0;
} if(amt < || amt > account->balance) {
return 0.0;
} double balance_tmp = account->balance;
sleep();
balance_tmp -= amt;
account->balance = balance_tmp; return amt;
} /** 存款: 返回存款的金额 */
double atm_account_Desposit(atm_Account *account, double amt)
{
if(NULL == account){
return 0.0;
}
if(amt < ){
return 0.0;
} double balance_tmp = account->balance;
sleep();
balance_tmp += amt;
account->balance = balance_tmp; return amt;
} /** 查看账户余额 */
double atm_account_BalanceGet(atm_Account *account)
{
if(NULL == account){
return 0.0;
} double balance_tmp = account->balance;
return balance_tmp;
}
atm_account.h
#ifndef __ATM_ACCOUNT_H__
#define __ATM_ACCOUNT_H__ #include <math.h>
#include <malloc.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h> /** 账户信息 */
typedef struct {
int code; ///< 银行账户的编码
double balance; ///< 账户余额
}atm_Account; /** 创建账户 */
extern atm_Account *atm_account_Create(int code, double balance);
/** 销毁账户 */
extern void atm_account_Destroy(atm_Account *account);
/** 取款 */
extern double atm_account_Withdraw(atm_Account *account, double amt);
/** 存款 */
extern double atm_account_Desposit(atm_Account *account, double amt);
/** 查看账户余额 */
extern double atm_account_BalanceGet(atm_Account *account); #endif
atm_handler.c
#include "atm_handler.h" /** 定义取款操作的线程运行函数 */
void *atm_handler_Withdraw(void *arg)
{
atm_handler_t *handler_tmp = (atm_handler_t *)arg;
double amt = atm_account_Withdraw(handler_tmp->account, handler_tmp->amt); printf("%10s(0x%lu) withdraw %f from account %d\n", handler_tmp->name, pthread_self(), amt, handler_tmp->account->code); return (void *);
} /** 定义存款操作的线程运行函数 */
void *atm_handler_Desposit(void *arg)
{
atm_handler_t *handler_tmp = (atm_handler_t *)arg;
double amt = atm_account_Desposit(handler_tmp->account, handler_tmp->amt); printf("%10s(0x%lu) deposit %f from account %d\n", handler_tmp->name, pthread_self(), amt, handler_tmp->account->code); return (void *);
} /** 定义检查银行账户的线程运行函数 */
void *atm_handler_AccountCheck(void *arg)
{
return (void *);
} /** 账户操作主函数 */
atm_error_t atm_handler_main(void)
{
int err;
pthread_t boy, girl;
atm_Account *account = atm_account_Create(, );
if(NULL == account){
return ATM_ERROR_ACCOUNT_CREATE;
} atm_handler_t usr1, usr2;
strcpy(usr1.name, "boy");
usr1.account = account;
usr1.amt = ; strcpy(usr2.name, "girl");
usr2.account = account;
usr2.amt = ; /** 启动两个线程(boy 和 girl 线程)同时去操作同一个银行账户 */
if((err = pthread_create(&boy, NULL, atm_handler_Withdraw, (void *)&usr1)) != ) {
perror("pthread create error");
} if((err = pthread_create(&girl, NULL, atm_handler_Withdraw, (void *)&usr2)) != ) {
perror("pthread create error");
} /** 主线程阻塞 */
pthread_join(boy, NULL);
pthread_join(girl, NULL); printf("account balance: %f\n", atm_account_BalanceGet(account));
atm_account_Destroy(account); return ATM_ERROR_NONE;
}
atm_handler.h
#ifndef __ATM_HANDLER_H__
#define __ATM_HANDLER_H__ #include "atm_account.h"
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h> typedef enum {
ATM_ERROR_NONE,
ATM_ERROR_ACCOUNT_CREATE
}atm_error_t; /** 账户操作结构体 */
typedef struct {
char name[]; ///< 操作人的姓名
atm_Account *account; ///< 操作的账户
double amt; ///< 操作的金额
}atm_handler_t; extern atm_error_t atm_handler_main(void); #endif
atm_test.c
#include "atm_handler.h" int main(void)
{
atm_handler_main();
return ;
}
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
编译运行结果:

三十九、Linux 线程——线程的同步和互斥的更多相关文章
- 孤荷凌寒自学python第三十九天python 的线程锁Lock
孤荷凌寒自学python第三十九天python的线程锁Lock (完整学习过程屏幕记录视频地址在文末,手写笔记在文末) 当多个线程同时操作一个文件等需要同时操作某一对象的情况发生时,很有可能发生冲突, ...
- Java进阶(三十九)Java集合类的排序,查找,替换操作
Java进阶(三十九)Java集合类的排序,查找,替换操作 前言 在Java方向校招过程中,经常会遇到将输入转换为数组的情况,而我们通常使用ArrayList来表示动态数组.获取到ArrayList对 ...
- Gradle 1.12用户指南翻译——第三十九章. IDEA 插件
本文由CSDN博客万一博主翻译,其他章节的翻译请参见: http://blog.csdn.net/column/details/gradle-translation.html 翻译项目请关注Githu ...
- centos shell编程5 LANMP一键安装脚本 lamp sed lnmp 变量和字符串比较不能用-eq cat > /usr/local/apache2/htdocs/index.php <<EOF重定向 shell的变量和函数命名不能有横杠 平台可以用arch命令,获取是i686还是x86_64 curl 下载 第三十九节课
centos shell编程5 LANMP一键安装脚本 lamp sed lnmp 变量和字符串比较不能用-eq cat > /usr/local/apache2/htdocs/ind ...
- “全栈2019”Java第三十九章:构造函数、构造方法、构造器
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...
- NeHe OpenGL教程 第三十九课:物理模拟
转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线 ...
- SQL注入之Sqli-labs系列第三十八关、第三十九关,第四十关(堆叠注入)
0x1 堆叠注入讲解 (1)前言 国内有的称为堆查询注入,也有称之为堆叠注入.个人认为称之为堆叠注入更为准确.堆叠注入为攻击者提供了很多的攻击手段,通过添加一个新 的查询或者终止查询,可以达到修改数据 ...
- 第三百三十九节,Python分布式爬虫打造搜索引擎Scrapy精讲—Scrapy启动文件的配置—xpath表达式
第三百三十九节,Python分布式爬虫打造搜索引擎Scrapy精讲—Scrapy启动文件的配置—xpath表达式 我们自定义一个main.py来作为启动文件 main.py #!/usr/bin/en ...
- WPF,Silverlight与XAML读书笔记第三十九 - 可视化效果之3D图形
原文:WPF,Silverlight与XAML读书笔记第三十九 - 可视化效果之3D图形 说明:本系列基本上是<WPF揭秘>的读书笔记.在结构安排与文章内容上参照<WPF揭秘> ...
- 微信小程序把玩(三十九)navigation API
原文:微信小程序把玩(三十九)navigation API 演示效果也看到了小程序也就提供这几个处理导航控制.值得注意的是只能同时导航五个页面 主要属性: 导航条一些方法 wx.setNavigati ...
随机推荐
- PHP日志切割shell
#!/bin/bash#此脚本用于自动分割php日志,error.log#每天00:01执行此脚本 将前一天的errors.log重命名为errors-xxxx-xx-xx.log格式,并重新打开日志 ...
- Apache虚拟主机+AD压力测试
<Directory "/usr/local/awstats/wwwroot"> Options NoneAllowOverride None Order allow, ...
- D: Starry的神奇魔法(矩阵快速幂)
题目链接:https://oj.ismdeep.com/contest/Problem?id=1284&pid=3 D: Starry的神奇魔法 Time Limit: 1 s Me ...
- rdesktop ERROR: CredSSP: Initialize failed, do you have correct kerberos tgt initialized ? Failed to connect, CredSSP required by server
错误信息: ERROR: CredSSP: Initialize failed, do you have correct kerberos tgt initialized ? Failed to co ...
- 洛谷P4307 球队收益
题意:有n个球队,m场比赛. 每个球队都已经有些胜负场次了. 每个球队的收益为Ci * wini2 - Di * losei2. 求最小可能总收益. 解: 先看出一个模型:用一流量代表一个胜场,每场比 ...
- A1117. Eddington Number
British astronomer Eddington liked to ride a bike. It is said that in order to show off his skill, h ...
- JavaScript深入之作用域链
前言 在 <javascript深入之执行上下文栈> 中讲到,当javascript代码执行一段可执行代码(executable code)时,会创建对应的执行上下文(execution ...
- MD5加密解密类(asp.net)&使用MD5过时处理
加密类 #region ========加密======== /// <summary> /// 加密 /// </summary> /// <param name=&q ...
- python pip NameError:name 'pip' is not defined”
https://www.jianshu.com/p/f57f98ebcb21 问题: 如果直接在命令行里面输入pip或者pip3,提示:(如图1) “NameError:name 'pip' is n ...
- 使用python制作验证码
方法一 简单型:使用random模块制作一个随机字母与数字的验证码 import random def make_code(n): res='' for i in range(n): num=str( ...