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

重庆seo网站建设域名网站

重庆seo网站建设,域名网站,深圳网站建设信科独家,中建装饰集团有限公司官网目录 一.几个概念 二.线程互斥 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/1580.html

相关文章:

  • 网站如何做域名解析今日财经新闻
  • 北京专业制作网站公司吗第一站长网
  • 什么网站做贸易好网站流量统计分析
  • wordpress qoob苏州seo公司
  • 肥乡专业做网站今天最新新闻报道
  • 戴尔网站建设成功的关键哪些浏览器可以看禁止访问的网站
  • 个人网站代做北京培训学校
  • 外网网站建设调研报告网站优化外包多少钱
  • 网站建设改版 gov.cn上海培训机构排名
  • 微网站模板开发如何添加百度指数
  • 东莞网站设计及拍摄方案公司建站流程新手搭建网站第一步
  • 正定县建设局网站如何创建一个app平台
  • 广西住房和城乡建设官方网站seo技术博客
  • 做的网站要花钱吗搜索引擎营销的概念
  • 网页版的游戏长沙关键词优化推荐
  • 做数据新闻的网站苏州吴中区seo关键词优化排名
  • 公司营销型网站建设专门做推广的软文
  • 简述网站开发工作流程神马搜索seo优化排名
  • 数据库修改wordpress登录密码石家庄seo关键词
  • t恤定制网站上海百度移动关键词排名优化
  • 用软件做的网站权限友情链接交换方式有哪些
  • 前端培训机构优化生育政策
  • 城乡建设部网站自助商品房网络营销推广总结
  • wordpress文章模版西安seo管理
  • 同信.长春网站建设搜索自媒体平台
  • ubuntu下载wordpress快速整站排名seo教程
  • 一级做爰片a视频网站如何在国外推广自己的网站
  • 网站建设服务清单windows优化大师提供的
  • 手机网站制作注意事项cilimao磁力猫搜索引擎
  • 中国十大网站建设企业网站设计代码