当前位置: 首页 > news >正文

濮阳网站建设在哪做文职培训机构前十名

濮阳网站建设在哪做,文职培训机构前十名,做网站上时需要3d预览功能,安徽省住房与城乡建设厅网站目录 一.几个概念 二.线程互斥 1.定义并初始化锁 2.加锁 3.解锁 4.销毁锁 三.互斥锁的本质 1.xchg的原子性 2.加锁的过程 3.解锁的过程 四.可重入VS线程安全 五.死锁 1.死锁的概念 2.具体实例 3.死锁产生的四个必要条件 4.解决或避免死锁 六.线程同步 七.…

目录

一.几个概念

二.线程互斥

1.定义并初始化锁 

2.加锁 

3.解锁 

4.销毁锁

三.互斥锁的本质 

1.xchg的原子性

2.加锁的过程

3.解锁的过程

四.可重入VS线程安全

五.死锁

1.死锁的概念

 2.具体实例

 3.死锁产生的四个必要条件

4.解决或避免死锁

六.线程同步 

七.生产者消费者模型  

1.概念

2.意义

八.条件变量 

1.定义并初始化条件变量

2.等待条件变量

​编辑

3.唤醒等待条件变量的一个或多个线程

 九.条件变量的细节问题


一.几个概念

  1. 临界资源:任何一个时刻,只允许一个执行流访问的共享资源
  2. 临界区:访问(read/write)临界资源的代码
  3. 互斥:保护临界资源的一种访问方式,即任何时刻,保证只有一个执行流进入临界区,访问临界资源
  4. 原子性:一个操作的性质,该操作不会被调度机制打断,只有未完成和已完成两种状态

C++语言中的--操作会转换为三条汇编语句:

  1. 将内存中的数据mov到CPU的寄存器
  2. 对寄存器中的数据dec(减1)
  3. 将寄存器中的数据写入到内存

一条汇编语句才是原子的,因此a--这句代码不是原子的!!!

 举例:两个线程并发对int a = 10进行++操作。线程1将10从内存拷贝到寄存器,进行+1操作,正要准备写2回到内存时,线程1被切换了,它会将寄存器内的值保存到CPU中。线程2从内存中读取到的还是10,进行若干次++操作,加到了100,并将100写回了内存。此时线程1再次被调度,从PCB中恢复硬件上下文,接着上一次未做完的工作,将寄存器中的11写回到内存。线程2好不容易把a加到100,现在一把回到解放前。出现以上问题的原因是,++操作不是原子的,数据从内存到寄存器,从寄存器到内存的过程没有一次性完成,被线程调度打断了。

内存中的数据是共享的,寄存器中的上下文是线程私有的,数据不一致就是指,上下文数据和内存中的共享数据不一致。

二.线程互斥

数据不一致问题,是因为多线程并发访问临界区,访问临界资源。所以只需保证,任一时刻,只有一个线程访问临界区,即可实现对临界资源的保护,以上的资源保护方式叫做互斥,互斥可以通过对临界区加互斥锁的技术手段来完成。

每个线程访问临界区,都必须先加锁,只有加锁成功,才能访问临界区,否则会阻塞等待。这是大家(线程或者编写代码的用户)都应该遵守的规则,如果有的线程遵守,有的不遵守,那锁便失去了意义。

1.定义并初始化锁 

定义并初始化全局的锁: 

定义并初始化局部的锁: 

2.加锁 

  1. 尽可能给少的代码加锁
  2. 一般给临界区加锁
  3. 访问临界区的线程都必须加锁,大家都应遵守这套规则
  4. 任何时刻,只会有一个线程申请加锁成功
  5. 锁也是临界资源,但申请加锁的操作本身就是原子的,所以申请加锁不会出现数据不一致问题,而导致多个线程申请锁成功。
  6. 一个线程加锁成功后,访问临界区,也会发生线程切换。但其它申请锁的线程会在pthread_mutex_lock上阻塞等待,无法访问临界区。加锁间接实现了线程访问临界区的原子性。
  7. 加锁的一般原则:谁加锁,谁解锁

3.解锁 

4.销毁锁

全局锁无需销毁,局部锁要及时销毁:

三.互斥锁的本质 

1.xchg的原子性

计算机通常会提供xchg汇编指令(硬件支持对应机器码),其作用是将寄存器内容和内存单元的内容进行交换。如果机器不支持exchange指令,那我们用户想要完成同样的工作,只能先将寄存器内容备份到另一个寄存器,再将内存拷贝到寄存器,最后将备份的内容拷贝到内存,分三步完成。但机器支持xchg指令,就只需要一步,这意味这,它是原子的。

2.加锁的过程

可以简单认为互斥锁就是一个值为变量,值为1表示可以被申请,值为0表示被占用

1.将某个寄存器的内容置0

2.使用xchg交换寄存器和mutex的内容->寄存器内容变为mutex的值,mutex变为0

3.判断寄存器内容是否大于0,如果大于0,则成功返回,否则挂起等待

只有第二步涉及到访问内存中的共享资源,而第二步又是原子的,所以整个加锁过程就是原子的。

内存中的mutex是线程共享的,寄存器中的上下文是线程私有的。xchg的本质是将共享资源mutex的数据交换到上下文中,属于线程自己。互斥锁的“1”就像一个令牌,谁拥有了“1”,谁就拥有了锁,即使线程被切换,它也会将上下文保存到PCB中打包带走。

3.解锁的过程

1.将1mov到内存的mutex中

2.唤醒等待mutex的线程(只不过从是从阻塞状态唤醒,可以被CPU调度,不是直接把锁分配给它),并成功返回

  

可以看出,解锁也是原子的

四.可重入VS线程安全

  1. 一个函数被多个执行流进入,称该函数被重入了。如果因为函数被重入而使程序行为不符合预期(崩溃或者数据不一致),称为该函数不可重入;否则,则称该函数可重入
  2. 多线程并发访问共享资源时,程序的行为符合预期,则称该线程是安全的。
  3. 线程安全描述的是线程的特征,可重入描述的是函数的特征。
  4. 多线程调用不可重入函数会导致线程不安全,多线程调用可重入函数不会导致线程不安全

五.死锁

1.死锁的概念

一组进程中的各个进程均占有不会释放的资源,但因为相互申请被其他进程所占用不会释放的资源,而处于的一种永久等待的状态。简而言之,死锁就是线程等待一个永远都得不到的锁

 2.具体实例

实例1:现有某个共享资源,规定线程访问它需要持有锁1和锁2。线程A欲要访问该资源,已经持有锁1,正在申请锁2;线程B也想访问该资源,已经持有锁2,正在申请锁1。线程A和线程B都无法集齐两把锁,也都不放弃手中的锁,导致线程A和线程B都被阻塞挂起,永远不会被调度。

以上是两把锁造成的死锁,实际上一把锁也能造成死锁

实例2:由于用户的粗心,将解锁代码写成加锁,导致线程等待自己手中的锁,但它永远等不到

 3.死锁产生的四个必要条件

  1. 互斥条件:使用锁以达到访问共享资源互斥
  2. 请求与保持条件:线程在申请锁的同时,对已获得的锁保持不放
  3. 不剥夺条件:一个线程手中的锁在使用完之前,不会被其它线程强行释放
  4. 循环等待条件:A找B要,B找A要

4.解决或避免死锁

破坏产生死锁的4个条件之一即可:

  1. 破坏互斥条件。使用锁是因为要保护共享资源,在条件允许的情况下,让每个线程私有一份资源,这样就不必使用锁来保证互斥了
  2. 破坏请求与保持条件。如果一个线程申请锁不成功,就把持有的锁都释放掉
  3. 破坏不剥夺条件。线程A想申请线程线程B手中的,管理线程检测到死锁,强行将线程B的锁释放
  4. 破坏循环等待条件。如果多线程要申请相同的锁,建议按照同样的次序申请

用户编码建议:

  1. 能不用锁就不用锁
  2. 如果要线程需要申请多个锁,尽量按照顺序一次性申请到位,不要分批申请

六.线程同步 

同步:在临界资源使用安全的前提下,让多线程执行具有一定的顺序性,以保证合理使用资源,解决线程饥饿问题。线程同步使用条件变量完成。

互斥能保证资源的安全,同步让资源使用更加高效。

七.生产者消费者模型  

1.概念

生产者消费者模型是多线程并发的一种经典设计模式。分为两种角色:

生产者:产生数据的线程,将产生的数据放置到共享的内存空间

消费者:从共享的内存空间取数据进行处理

生产者和消费者之间的关系如下:

生产者和生产者:互斥。同时向一块内存写入,会出现数据不一致问题(覆盖或混乱)

消费者和消费者:互斥。同时从一块内存读数据,会出现数据不一致问题(混乱)

生产者和消费者:互斥和同步。同时写和读,会导致消费者得到的数据残缺不全,所以需要互斥;生产者生产完成后再通知消费者来取,避免消费者做一些浪费资源的行为,所以需要同步。

注意:生产是指将数据放到交易场所,消费是指从交易场所拿走数据

2.意义

我们调用函数的目的,就是让函数作为消费者,处理传递给它的数据。但是如果函数的处理过程没有完成,调用处的代码就无法向下执行。

  1. 实现生产过程和消费过程执行解耦。共享的内存空间相当于一块缓存,只要缓存没有打满或者缓存不为空,消费和生产过程就不会相互影响,支持生产消费忙闲不均
  2. 提高数据处理的效率。生产者生产数据,前提是要获取数据,消费者取走数据后,还要进行处理。消费者的数据一般从具体场景中得来,例如从网络读取,也就是说,获取数据本身也要花费时间,消费者处理数据也要花时间。多生产和多消费模型在任何一个时刻只允许一个线程进入,高效并不体现在同步和互斥,而是使得获取数据和处理数据更好地并发。

八.条件变量 

1.定义并初始化条件变量

2.等待条件变量

3.唤醒等待条件变量的一个或多个线程

 前者是唤醒所有的线程,或者是唤醒队头的线程

 九.条件变量的细节问题

  1. 在加锁和解锁之间要往往是要访问临界资源,但资源不一定是就绪的,所以需要有if语句这样的判断。如果判断条件不满足,什么也不做,线程会再次执行加锁,判断,解锁这样的无效工作。为了避免资源浪费,在条件不满足时,让线程在条件变量上阻塞等待。
  2. 让线程进行等待的时候,会自动释放锁
  3. 线程被唤醒的时候,是在临界区内唤醒的,当线程被唤醒,线程在pthread_cond_wait返回的时候,要重新申请锁  
  4. 当线程被唤醒的时候,重新申请锁本质是也要参与锁的竞争的
http://www.ds6.com.cn/news/102810.html

相关文章:

  • 澄迈网站建设360搜索引擎网址
  • 希音电商网站全国疫情最新情况公布
  • 商务网站运营与管理云南网站建设快速优化
  • 那些网站容易做淘宝推广永久免费用的在线客服系统
  • 甘肃商城网站建设南京百度网站快速优化
  • 360平台怎么做网站优化小程序开发平台官网
  • asp做网站很少在线生成个人网站源码
  • 织梦如何仿手机网站源码大学生创新创业大赛
  • 四川攀枝花网站建设体验营销策划方案
  • 西安旅游攻略必去景点南京搜索引擎推广优化
  • 网站开发素材代码seo新手快速入门
  • 济南百度公司做网站吗产品运营方案
  • uc下载的视频禁止自动播放百度seo推广怎么做
  • 威联通做网站网络营销的基本特征有哪七个
  • 南京好的网站设计技术教程优化搜索引擎整站
  • 北京建设网网站搜索引擎查关键词排名的软件
  • 南充建网站的资料三只松鼠搜索引擎推广
  • 用jsp做的动态网站河南专业网站建设
  • Wordpress本地上载系统优化的意义
  • 池州网站建设网站建设成都自然排名优化
  • wordpress模板在哪搜索引擎优化seo培训
  • 武锡网站建设生购房政策百度app安装下载免费
  • 北京两学一做网站千锋教育学费一览表
  • asp.net做网站后台百度服务商
  • 珠海网站公司哪家好百度热线电话
  • 找做网站的人进入百度搜索首页
  • 广州天河网站制作网络广告的计费方式
  • 做服装有哪些好的网站有哪些方面外贸网络营销平台
  • 宁波外贸网站开发自助建站申请
  • 企业qq登录谷歌seo靠谱吗