Linux下线程的同步与互斥

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

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

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

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

一,mutex

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

初始化好了怎么加锁?:

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

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

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

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

其结果也是一样的:

二,cond(同步)

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

同步的意义:

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

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

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

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

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

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

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

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

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

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

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

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

相关推荐
流星5211229 小时前
GC 如何判断对象该回收?从可达性分析到回收时机的关键逻辑
java·jvm·笔记·学习·算法
JanelSirry10 小时前
我的应用 Full GC 频繁,怎么优化?
jvm
JH307310 小时前
jvm,tomcat,spring的bean容器,三者的关系
jvm·spring·tomcat
DKPT14 小时前
JVM直接内存和堆内存比例如何设置?
java·jvm·笔记·学习·spring
siriuuus14 小时前
JVM 垃圾收集器相关知识总结
java·jvm
小满、16 小时前
什么是栈?深入理解 JVM 中的栈结构
java·jvm·1024程序员节
百花~1 天前
JVM(Java虚拟机)~
java·开发语言·jvm
每天进步一点点dlb1 天前
JVM中的垃圾回收算法和垃圾回收器
jvm·算法
漫漫不慢.1 天前
蓝桥杯-16955 岁月流转
java·jvm·蓝桥杯
boy快快长大2 天前
【JVM】线上JVM堆内存报警,占用超90%
jvm