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 线程——线程的同步和互斥的更多相关文章

  1. 孤荷凌寒自学python第三十九天python 的线程锁Lock

    孤荷凌寒自学python第三十九天python的线程锁Lock (完整学习过程屏幕记录视频地址在文末,手写笔记在文末) 当多个线程同时操作一个文件等需要同时操作某一对象的情况发生时,很有可能发生冲突, ...

  2. Java进阶(三十九)Java集合类的排序,查找,替换操作

    Java进阶(三十九)Java集合类的排序,查找,替换操作 前言 在Java方向校招过程中,经常会遇到将输入转换为数组的情况,而我们通常使用ArrayList来表示动态数组.获取到ArrayList对 ...

  3. Gradle 1.12用户指南翻译——第三十九章. IDEA 插件

    本文由CSDN博客万一博主翻译,其他章节的翻译请参见: http://blog.csdn.net/column/details/gradle-translation.html 翻译项目请关注Githu ...

  4. 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 ...

  5. “全栈2019”Java第三十九章:构造函数、构造方法、构造器

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...

  6. NeHe OpenGL教程 第三十九课:物理模拟

    转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线 ...

  7. SQL注入之Sqli-labs系列第三十八关、第三十九关,第四十关(堆叠注入)

    0x1 堆叠注入讲解 (1)前言 国内有的称为堆查询注入,也有称之为堆叠注入.个人认为称之为堆叠注入更为准确.堆叠注入为攻击者提供了很多的攻击手段,通过添加一个新 的查询或者终止查询,可以达到修改数据 ...

  8. 第三百三十九节,Python分布式爬虫打造搜索引擎Scrapy精讲—Scrapy启动文件的配置—xpath表达式

    第三百三十九节,Python分布式爬虫打造搜索引擎Scrapy精讲—Scrapy启动文件的配置—xpath表达式 我们自定义一个main.py来作为启动文件 main.py #!/usr/bin/en ...

  9. WPF,Silverlight与XAML读书笔记第三十九 - 可视化效果之3D图形

    原文:WPF,Silverlight与XAML读书笔记第三十九 - 可视化效果之3D图形 说明:本系列基本上是<WPF揭秘>的读书笔记.在结构安排与文章内容上参照<WPF揭秘> ...

  10. 微信小程序把玩(三十九)navigation API

    原文:微信小程序把玩(三十九)navigation API 演示效果也看到了小程序也就提供这几个处理导航控制.值得注意的是只能同时导航五个页面 主要属性: 导航条一些方法 wx.setNavigati ...

随机推荐

  1. 牛客练习赛43 Tachibana Kanade Loves Game (简单容斥)

    链接:https://ac.nowcoder.com/acm/contest/548/F来源:牛客网 题目描述 立华奏是一个天天打比赛的萌新. 省选将至,萌新立华奏深知自己没有希望进入省队,因此开始颓 ...

  2. Spring -- 自定义转换器

    Spring 定义了 3 种类型的转换器接口,实现任意一个转换器接口都可以作为自定义转换器注册到 ConversionServiceFactoryBean 中: Converter<S,T> ...

  3. goroutine与调度器

    29 November 2013 by skoo 我们都知道Go语言是原生支持语言级并发的,这个并发的最小逻辑单元就是goroutine.goroutine就是Go语言提供的一种用户态线程,当然这种用 ...

  4. n+lognlogV查找最大值

    来自Blogewoosh #6. 啃了一下,写个翻译吧. 问题:你有一个数组,你不知道每个元素的大小,但是能够提出询问:a[x]是否>=v?你需要找出这个数组的最大值,只能询问n + lognl ...

  5. 【洛谷P4462】异或序列

    题目大意:给定一个长度为 N 的序列,有 M 组询问,每组询问查询区间 [l,r] 内异或和等于给定常数 K 的区间组数. 题解:对于异或和问题,一般先进行前缀和处理,转化为两个点的的关系.因此,经过 ...

  6. python描述器

    描述器定义 python中,一个类实现了__get__,__set__,__delete__,三个方法中的任何一个方法就是描述器,仅实现__get__方法就是非数据描述器,同时实现__get__,__ ...

  7. 将本地html文件拖到IE8浏览器无法打开,直接弹出一个下载的对话框

    查看一下注册表[HKEY_CLASSES_ROOT\.htm]和[HKEY_CLASSES_ROOT\.html]的ContentType值是否都为“text/html”

  8. RenderTree渲染树

    RenderTree渲染树对类中的静态成员有很重要的关系,这个和多态是有很重要的关系,举个简单的例子,在游戏中,马里奥需要渲染,蘑菇也需要渲染,怪兽也需要渲染,其是串在一个树上的,但是不同的类型怎么将 ...

  9. postman接口测试

    拿到API,直接拖到postman里面,修改一下params,send之后查看结果返回 说明一下: 1.get的内容,写入测试URL 和API地址 2.点击bulkEdit,编辑请求的key+valu ...

  10. HTML学习笔记Day16

    一.CSS 3D 1.什么是3d的场景呢? 2d场景,在屏幕上水平和垂直的交叉线x轴和y轴 3d场景,在垂直于屏幕的方法,相对于2d多出个z轴 Z轴:靠近屏幕的方向是正向,远离屏幕的方向是反向 2.C ...