Linux下线程的同步与互斥

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

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

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

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

一,mutex

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

初始化好了怎么加锁?:

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

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

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

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

其结果也是一样的:

二,cond(同步)

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

同步的意义:

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

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

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

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

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

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

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

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

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

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

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

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

相关推荐
无敌最俊朗@2 小时前
02-SQLite 为了防止多人同时乱写,把整个数据库文件“当一本账本加锁”
jvm·数据库·oracle
白露与泡影5 小时前
Spring Boot项目优化和JVM调优
jvm·spring boot·后端
Boop_wu7 小时前
[Java EE] 多线程 -- 初阶(2)
java·开发语言·jvm
Chan169 小时前
【 Java八股文面试 | JVM篇 内存结构、类加载、垃圾回收与性能调优 】
java·jvm·spring boot·后端·spring·idea
百***926514 小时前
java进阶1——JVM
java·开发语言·jvm
虫师c14 小时前
字节码(Bytecode)深度解析:跨平台运行的魔法基石
java·jvm·java虚拟机·跨平台·字节码
坐吃山猪1 天前
第2章-类加载子系统-知识补充
jvm
百***92021 天前
java进阶1——JVM
java·开发语言·jvm
Pluchon1 天前
硅基计划6.0 柒 JavaEE 浅谈JVM&GC垃圾回收
java·jvm·数据结构·java-ee·gc
初学小白...1 天前
JVM入门知识点
java·服务器·jvm