Linux下线程的同步与互斥

开头我们来写一个简单的程序,实现用多线程的方式来抢票,代码如下:

运行完结果后发现,我这只有一万张票,在if条件判断里我也做了判断,怎么会干到-2来了呢?

运用线程的理论知识我们知道,ticketnum在线程中属于共享资源,它不具有原子性,在我们需要对变量进行减减的时候,内存会将变量存入cpu中减减,然后再把减完后的内容写入内存里三步,

但减减完的数据还没写入内存的时候,进程就被切换了,也就是上面三步线程没做完,所以不具备原子性,当然我们做if判断的时候,也是一种计算也是要进cpu的,在最后数据都只是1的时候,四个线程都进去了,随着变量被减减,他就会被减到负数。为了避免这种情况,可以使用互斥锁;

一,mutex

锁的使用最好是在临界区内,锁最好涵盖代码少一点,要不然会影响运行效率,如果使用全局锁,可用PTHREAD_MUTEX_TNITIALIZER来初始化锁,这样只需要声明:

初始化好了怎么加锁?:

可以看到,加锁解锁都得在临界区内加,并且不能大块代码的加锁。

可以看到,对临界区加锁之后,变量减减就变成具有原子性的了,加锁的本质就是对资源进行预定,整体使用资源,如果申请锁的时候,锁被别人拿走了,这时候其他线程就会阻塞等待直到前面线程运行完再竞争,线程在访问临界区代码的时候,可以不可以切换??可以切换!!

我被切走的时候,别人能进来吗??不能!我是抱着锁,被切换的!!不就是串行吗!效率低的原因!原子性!上面是全局初始化锁的方式,不用我们用init和destory方法,下面就是用局部初始化锁的方式书写代码:

首先对锁进行初始化,再在结束位置销毁锁,

其结果也是一样的:

二,cond(同步)

根据mutex的学习,来映伸出下一个问题,当一个线程拿完锁回到队列中再次与其他线程竞争锁的时候,会有部分概率重复使用锁(饥饿问题) ,其他线程会长时间得不到资源,会导致程序运行效率不高,这时候可以使用同步的方法来解决,就好比排队一样,排完队领完东西还要再领就得重新在队伍后面排队,这就叫同步

同步的意义:

互斥可以保证安全性,但是安全不一定合理高效

同步是保证安全的情况下,让代码变得合理和高效。

首先我们先来了解对应接口:首先来介绍同步的初始化,看图:

可以发现,他和mutex的初始化是一样的,可以全局初始化也可以局部初始化,在全局使用初始化可以不用调用init和destory函数。

下一个接口,让指定的线程在指定的环境变量等待,如果别人不唤醒就一直等。

signal接口,可以唤醒在特定条件变量下的一个线程:

broadcast可以唤醒特定条件变量下指定的所有线程。

条件变量是一个用来进行线程同步的特性,内部要维护线程队列。

下面利用之前的抢票代码来做线程同步的接口练习:

可以看到,我先把票数设为零,线程都会去wait这里等待:

可以看到线程都在阻塞等待,这时候我们可以通过放票然后唤醒线程的方式来抢票:

可以看到线程被唤醒但是没执行,是因为在wait那里会重新申请和释放锁,就相当于已经有锁了但是又去申请锁,代码就会被挂起,这个后面细讲,在while那边再次解锁来让我们看到测试结果先:

相关推荐
香蕉大香蕉(06敬畏市场)2 小时前
高频八股 · Java 并发编程(10):异步、ThreadLocal 与虚拟线程(收官)
java·开发语言·网络·jvm·python·ai·实习
wuminyu3 小时前
JVM规范学习总结-Class文件结构
java·linux·c语言·jvm·c++
酌沧19 小时前
MemT让记忆成为模型内生能力
jvm·人工智能·算法
wuminyu1 天前
JVM规范学习总结-Java源码经过javac编译后产物
java·linux·c语言·jvm·c++
学到老活到老2 天前
类已经加载了,为什么静态代码还没执行?
java·jvm
学到老活到老2 天前
写了 new,就一定会在堆上分配对象吗?
java·jvm
笨笨饿2 天前
# 59_CSDN博客自动写流程文章
linux·jvm·stm32·单片机·嵌入式硬件·mcu·51单片机
tedcloud1232 天前
Docker Compose 部署 Memos:从安装到备份恢复
linux·开发语言·jvm·后端·docker·容器·rust
螺蛳粉 螺蛳粉2 天前
大数据第四篇:事故复盘:移走 HBase 里 27 个 hadoop-2.10.2 jar 后,HMaster 半小时后“自杀“了【jar 事故复盘】
jvm·hadoop·hbase·异常处理·大数据运维·踩坑记录·事故复盘
wuminyu2 天前
JVM规范学习总结-JVM规范基本概念
java·linux·c语言·jvm·c++