三十九、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 ...
随机推荐
- 「SCOI2014」方伯伯的商场之旅 解题报告
「SCOI2014」方伯伯的商场之旅 我一开始的想法会被两个相同的集合位置去重给搞死,不过应该还是可以写的,讨论起来老麻烦. 可以先钦定在\(1\)号点集合,然后往后调整一部分. 具体一点,通过前缀和 ...
- 构建FTP服务
一.配置YUM仓库服务--------------YUM服务器------------------client------------------192.168.1.1 192.168.1.10[ro ...
- 【UNR #1】火车管理
题目描述 uoj 旗下有一个火车站,用来管理属于 uoj 的小火车. 火车站一共有 nn 条编号为 1,…,n1,…,n 的,只有一端的用来存放小火车的铁路,由于小火车特殊的构造,每条铁路可以停放无数 ...
- [CQOI2017]小Q的表格(数论+分块)
题目描述 小Q是个程序员. 作为一个年轻的程序员,小Q总是被老C欺负,老C经常把一些麻烦的任务交给小Q来处理.每当小Q不知道如何解决时,就只好向你求助. 为了完成任务,小Q需要列一个表格,表格有无穷多 ...
- codeforces #541 D. Gourmet choice(拓扑+并查集)
Mr. Apple, a gourmet, works as editor-in-chief of a gastronomic periodical. He travels around the wo ...
- 20165223《JAVA程序设计》第二周学习总结
20165223 <JAVA程序设计>第二周学习总结 教材学习内容总结 第二章要点 标识符与关键字 基本数据类型 类型转换运算 输入输出数据 数组 第三章要点 运算符与表达式 语句概述 i ...
- centos7 下解决mysql-server找不到安装包问题
第一步:安装从网上下载文件的wget命令 [root@master ~]# yum -y install wget 第二步:下载mysql的repo源 [root@master ~]# wget ht ...
- Typescript学习笔记(一)基础类型
为了面向ng2和前端未来,开始搞向ts,ts是微软出的一枚语言,作为es6的超集,他出的一些特性还是蛮好用的(略坑).对于我等纯前端(从开始就接触javascript)的人来说,真想说,这特么什么鬼. ...
- 使用 MongoDB 存储日志数据
使用 MongoDB 存储日志数据 线上运行的服务会产生大量的运行及访问日志,日志里会包含一些错误.警告.及用户行为等信息.通常服务会以文本的形式记录日志信息,这样可读性强,方便于日常定位问题 ...
- [bzoj1717][Milk Patterns 产奶的模式]
题目链接 思路 先求出后缀数组,并且求出LCP.二分一下长度len.check的时候就是看有没有连续的k个后缀的LCP大于len.也就是判断是不是有连续的k-1个height大于len. 代码 #in ...