理解并发程序的执行

53 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第7天,点击查看活动详情  Overview


复习

  • 并发程序 = 多个执行流、共享内存的状态机

本次主要内容

如何阅读理解并发程序

画状态机理解并发程序

互斥:希望保证两个线程不能同时执行一段代码

用读写实习共享内存上的互斥

问题:

image.png 可能会连续扣两次钱

0

image.png 一次失败尝试

image.png

简单的上锁(其实是锁不住的)

不能实现互斥,因为两个线程都可以同时改变锁的状态,看见锁和加锁这个操作不是原子性的,是分成两步的,所以线程不安全。

LOCK(上锁状态) UNLOCK(解锁状态)

处理器默认不保证load+store的原子性

正确性不明的奇怪尝试(Peterson算法)

线程(每个人)别的线程无法改变线程状态(store(改变状态):举一个旗子,贴一个牌子啥的 load(查看状态):查看旗子的颜色啥的)

并发程序麻烦的地方(不可见性):看到以后的状态是一个历史,并不是实时的状态,当你去做事情的时候,那就有可能被改掉了。

共享内存(物理世界)

peterson算法:

image.png 举旗子:我想上厕所

带有对方名字的帖纸:代表谁能真正进厕所,看上去是一个谦让行为,但是只有一个贴纸位置,所以往下看。。。

当两个人都想去的时候,互相谦让

限制:两个线程

上一个失败的例子就相当于,我想进厕所,我看一下厕所有没有人,我再进去,但是我看完之后,我只能闭着眼睛进去,但是这之间,有个人也进去了,那我们俩都进去了,就产生了并发问题。

所以要证明这个,也要证明我俩都想上厕所的时候是否互斥

证明:

两方都举旗子,我们俩都贴纸,A手快,B的名字先贴上去,B手慢了,把A贴上去了,把B自己的名字覆盖掉了,啊哈哈,那这时候看,上面写的A的名字,那就A进去啦,实际上这个算法还是自私的,谁手快谁进去。

#include "thread.h" #define A 1 #define B 2 atomic_int nested; atomic_long count; void critical_section() { long cnt = atomic_fetch_add(&count, 1); assert(atomic_fetch_add(&nested, 1) == 0); atomic_fetch_add(&nested, -1); } int volatile x = 0, y = 0, turn = A; void TA() { while (1) { /* PC=1 / x = 1;//举起旗子 / PC=2 / turn = B;//门上的标签 / PC=3 / while (y && turn == B) ; critical_section(); / PC=4 / x = 0;//放下旗子 } } void TB() { while (1) { / PC=1 / y = 1; / PC=2 / turn = A; / PC=3 / while (x && turn == A) ; critical_section(); / PC=4 */ y = 0; } } int main() { create(TA); create(TB); }

image.png