操作系统(2)进程、线程、锁
【摘要】
目录
1,进程和线程
2,线程调度
3,Linux系统的进程和线程
4,原子操作、同步、锁
5,可重入
6,过度优化 VS 线程安全
1,进程和线程
每个进程都有自己的独立内存空间。
线程,也可以成为轻量级进程,一个进程由一个到多个线程组成。
2,线程调度
CPU的运行被切割成时间片,每个时间片运行...
目录
1,进程和线程
每个进程都有自己的独立内存空间。
线程,也可以成为轻量级进程,一个进程由一个到多个线程组成。
2,线程调度
CPU的运行被切割成时间片,每个时间片运行一个线程,不断切换运行线程。
线程至少有3个状态:运行running、就绪ready、等待waiting
3,Linux系统的进程和线程
4,原子操作、同步、锁
一个独立的不被其他操作影响的操作叫原子操作。
线程是共享数据的,为了避免同时读写导致数据异常,需要对数据进行访问同步,即一个线程访问的时候另外一个线程不能访问,这样的访问就是原子操作。
同步的最常见方法就是锁。
常见的锁:信号量、互斥量、临界区、读写锁、条件变量
5,可重入
函数重入
函数可重入指的是,该函数重入之后,不会产生任何不良后果。
可重入函数的特点:
6,过度优化 VS 线程安全
(1)一些复杂的优化行为,会让锁失效。
案例一:将变量写入寄存器而不写回
编译器为了提高访问速度,将变量x写入寄存器而不写回,可能导致最终x的值是1,本来应该是2的。
案例二:交换指令顺序
编译器可能会为了提高效率而交换相邻两条无关指令的顺序,CPU的动态调度功能也会交换指令执行的顺序。
这样,最终结果可能就是r1=r2=0,本来是不可能这样的。
(2)使用volatile关键字,可以阻止编译器为了提高访问速度,将变量x写入寄存器而不写回,可以阻止编译器操作volatile变量的指令顺序。
所以,volatile可以解决案例一,但是无法解决案例二,因为CPU有动态调度。
(3)单例模式的double-check
案例三:还是交换指令顺序
这个是单例模式,申请一个对象,双重if判断是为了降低lock的调用,提高效率。
而(2)(3)的顺序是可以颠倒的,所以如果函数并发调用,就会有一个正在调用构造函数的对象的指针,被提供给调用方,从而引发错误。
CPU通常会提供一条屏障指令,用来组织指令交换顺序的时候穿过屏障,有的叫barrier,有的叫lwsync
例如,可以这样来解决上面的问题:
文章来源: blog.csdn.net,作者:csuzhucong,版权归原作者所有,如需转载,请联系作者。
原文链接:blog.csdn.net/nameofcsdn/article/details/120319751
【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)