Linux下线程的同步与互斥

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

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

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

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

一,mutex

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

初始化好了怎么加锁?:

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

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

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

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

其结果也是一样的:

二,cond(同步)

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

同步的意义:

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

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

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

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

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

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

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

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

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

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

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

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

相关推荐
期待のcode2 小时前
Java虚拟机的非堆内存
java·开发语言·jvm
jmxwzy6 小时前
JVM(java虚拟机)
jvm
Maỿbe6 小时前
JVM中的类加载&&Minor GC与Full GC
jvm
人道领域7 小时前
【零基础学java】(等待唤醒机制,线程池补充)
java·开发语言·jvm
小突突突7 小时前
浅谈JVM
jvm
饺子大魔王的男人9 小时前
远程调试总碰壁?局域网成 “绊脚石”?Remote JVM Debug与cpolar的合作让效率飙升
网络·jvm
天“码”行空19 小时前
java面向对象的三大特性之一多态
java·开发语言·jvm
独自破碎E1 天前
JVM的内存区域是怎么划分的?
jvm
期待のcode1 天前
认识Java虚拟机
java·开发语言·jvm
leaves falling1 天前
一篇文章深入理解指针
jvm