目录
4:自旋锁和信号量在临界区可以睡眠吗(sleep)?为什么?
一:进程和线程
1:进程和线程
1.1什么是进程?什么是线程?
-
进程是资源分配的最小单位,线程是cpu调度的最小单位
-
进程间地址空间独立,所以进程间通信,需要频繁的上下文切换,开销大
-
线程间共享内存数据,但栈独立,无需频繁的上下文切换,所以线程间通信开销小
-
多线程程序,只要有一个程序异常崩溃,整个进程就会死掉,而多进程中,一个进程异常,对其他进程没有影响
1.2:何时使用多进程?何时使用多线程?
-
对资源的利用和保护要求高,对cpu效率要求不高,使用多进程;
-
对cpu效率要求高,对资源的利用和保护要求不高,用多线程
1.3 进程有哪几种状态?
创建态、就绪态、运行态、阻塞态、终止态
1.4 进程间通信方式有哪些?以及各自的优缺点是什么?
-
管道(pipe):半双工通信,只能用于有血管关系的进程间进行通信。速度慢,容量有限
-
命名管道:可以用于无血缘关系的进程间进行通信,速度慢
-
内存映射(mmap):映射一段能够被其他内存访问的内存,速度快,数据量大
-
信号:用于通知进程某个事件已发生
-
信号量(sem_t):用来控制多个进程对于一个共享资源的访问,相当于锁机制,对于线程和进程间的同步手段
-
socket:常用于网络通信
-
消息队列:
1.5,线程同步方式有哪些?
-
互斥锁:等锁时,会被挂起,主动放弃cpu资源,等待锁。适用于临界区处理速度慢,锁持有时间长的场景
-
自旋锁:等锁时,不会挂起,忙轮训,一直占用cpu资源。适用于临界区处理速度快,锁持有的时间短,不希望线程在重新调度上花太多的成本。
-
读写锁:增加了共享资源的读取效率
-
信号量:可以使得多个线程,访问共享资源,增大了效率(生产者消费者模型)
-
条件变量:拿到锁,并满足条件时,才会进入临界区
1.6 什么是内核级线程?什么是用户级线程?
-
内核级线程:用户自己创建,内核并不知道用户级线程的存在。没有内核支持的线程系统内,一个用户级线程阻塞时,会导致整个进程阻塞,时间片分配单位为进程
-
用户级线程:由操作系统内核创建和撤销。内核维护进程及线程的上下文信息以及线程切换。一个线程阻塞,不会影响到其他内核级线程。
1.7 什么是僵尸进程?孤儿进程?守护进程?
-
僵尸进程:子进程运行结束,但是父进程没有调用wait或者waitpid函数回收子进程,使得子进程成为僵尸进程
-
孤儿进程:父进程先于子进程结束,导致子进程被1号进程init收养。
-
守护进程:故意让父进程结束,子进程被init收养,为守护进程。守护进程在后台执行,不与用户交互
1.8 僵尸进程有什么危害? 如何清理僵尸进程?
-
危害:占用系统资源,进程号,进程状态,cpu运行时间等信息无法释放。如果有大量的僵尸进程存在,可能会导致进程号不够用,使得无法创建新的子进程。
-
清理:杀死父进程,让init进程回收子进程; 父进程调用wait函数回收子进程
二:锁
1:阻塞和挂起和睡眠(slepp)的区别是什么?
-
阻塞:等待事件或者资源时,被动进入阻塞状态。主动放弃cpu,等待所需要的资源
-
挂起:挂起是一种主动行为,恢复也是主动地。系统中有时负荷过重(进程数过多),资源数相对不足,从而造成系统效率下降。此时需要挂起一部分进程以调度系统负荷,等系统中负荷减轻后在恢复被挂起进程的执行。挂起不会释放cpu
-
sleep(n),它表示用户线程放弃当前的cpu时间片,n秒后参与cpu使用。sleep(0)是有特殊含义的,它表示此时此刻我放弃cpu时间片,别人可以执行,然后马上参与cpu竞争。
-
挂起线程的意思就是你对主动对雇工说:“你睡觉去吧,用着你的时候我主动去叫你,然后接着干活”。
-
使线程睡眠(sleep)的意思就是你主动对雇工说:“你睡觉去吧,某时某刻过来报到,然后接着干活”。
-
线程阻塞的意思就是,你突然发现,你的雇工不知道在什么时候没经过你允许,自己睡觉了,但是你不能怪雇工,因为本来你让雇工扫地,结果扫帚被偷了或被邻居家借去了,你又没让雇工继续干别的活,他就只好睡觉了。至于扫帚回来后,雇工会不会知道,会不会继续干活,你不用担心,雇工一旦发现扫帚回来了,他就会自己去干活的。因为雇工受过良好的培训。这个培训机构就是操作系统。 ———————————————— 版权声明:本文为CSDN博主「小七mod」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:【并发基础】一篇文章带你彻底搞懂睡眠、阻塞、挂起、终止之间的区别_线程挂起和阻塞的区别_小七mod的博客-CSDN博客
2:驱动里面为什么要有并发,互斥的控制?如何实现?举个例子
-
实现并发是为了使得用户,看起来能够同时运行更多的进程。但是对于单核cpu来说,线程之间也是串行执行的。
-
并发对于共享资源的访问很容易导致竞争,所以实现了互斥机制,使得多个线程间有序互斥的访问共享资源。
-
可以利用互斥锁,自旋锁,读写锁,信号量,条件变量,原子操作,实现互斥。
3:自旋锁是什么?信号量是什么?有何异同?
-
自旋锁:只有一把锁,互斥的访问共享资源,没有拿到锁时,则忙轮训等待其他进程释放锁。自旋锁常用于临界区访问速度快的场景,减少cpu调度的开销。如果临界区访问时间长,则适用于互斥锁。
-
信号量:有多把锁,可以同时有多个线程访问共享资源,提高了资源的利用率。由于争用信号量的线程,在等待锁时,会则塞等待,自动放弃cpu资源,所以适用于临界区访问时间长的场景。
4:自旋锁和信号量在临界区可以睡眠吗(sleep)?为什么?
-
自旋锁不可以睡眠,信号量可以
-
因为自旋锁进制处理器抢占,信号量允许处理器抢占。 基于这个原因如果自旋锁在锁住后进入睡眠,由于不能进行处理器抢占,其他系统进程都不能获得cpu。但是如果是多核cpu,那么其他活动的cpu可以继续运行,并且有可能唤醒睡眠了的自旋锁。
-
而信号量在临界区睡眠时,由于其允许处理器抢占,可以运行其他进程线程
5:自旋锁和信号量可以用于中断吗?
-
信号量不可以用于中断,因为信号量中允许睡眠,而中断不能休眠。
-
自旋锁可以用于中断。在获取锁之前要先禁止本地中断(本cpu中断,对于多核处理器有多个cpu),否则可能导致死锁现象。
6:中断中为什么不可以睡眠(sleep)?
作者:灯珑 链接:Linux 内核为什么在中断里不能 sleep? - 知乎 来源:知乎 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
中断上下文中,任何休眠锁、以及sleep的操作是不被允许的。这是为什么呢?
先讲一下背景知识。
在x86-64架构中,中断需要通过门(gate),才能进入中断处理程序。与中断相关的门,分为中断门和陷阱门两种。其中,中断门不允许嵌套,而陷阱门允许中断嵌套。
因此,对于通过中断门的中断请求,在进入中断处理程序之前,处理器会禁用当前核心的所有中断(相当于执行cli指令),在中断处理程序返回之后,处理器又会执行sti指令。因此,在整个中断处理程序运行的过程中,外部的中断是不能到达这个核心的。
并且,进程切换的时钟信号是来自local apic定时器的,这是每个核心都有的定时器,它通过周期性的产生时钟中断,更新调度器的jiffies,从而触发调度器。
回到这个问题,如果我们在通过中断门的上下文中使用sleep,调度器会将当前核心上运行的进程调出去。但是,由于中断已经被禁止,从而会导致该核心收不到时钟中断的信号,再也不会周期性的发生进程调度。于是就会导致这个核心dead了。
综上所述,我们在中断上下文中不能使用sleep的原因就是,会导致核心无法收到新的时钟中断,从而无法正常进行进程调度。
对于穿过陷阱门的上下文来说,是可以sleep的,但是我们也非常不建议这样做。
7:读写锁是什么?
读共享,写独占,写锁优先级高。
如果有多个线程要读取共享资源时,可以有效提高资源的利用率
8:产生死锁的原因是什么?
多个进程或者线程,因争夺系统资源而产生相互等待的现象
-
一个线程拿到了锁,上锁之后,又再次上锁,这样会导致死锁
-
两个线程,线程A和线程B,两把锁,锁A和锁B。线程A拿到了锁A要去抢锁B,线程B拿到了锁B要去抢锁A。此时就会发生死锁
9:产生死锁的4个必要条件是什么?
-
互斥
-
占有某一个资源,且等待另一个资源
-
不可抢占
-
循环等待
10:死锁的处理方式有哪些?
-
预防死锁
-
资源有序分配(线程同步)
-
可剥夺资源
-
-
解除死锁
-
剥夺资源:从其他进程剥夺死锁进程所需的资源,已解除死锁状态
-
撤销进程
-
11:如何避免死锁?
-
加锁顺序
-
加锁时限:线程尝试获取锁的时候加上一定的时限,超过时限则放弃对该锁的请求,并释放自己占有的锁
-
给线程设置优先级
12:单核机器上,写多线程程序,是否需要上锁?为什么?
需要
三:内存
1:什么是代码段,数据段,bss段,堆,栈?
-
代码段:存放执行代码的一段区域
-
数据段:保存已经被初始化的全局变量,已初始化为非零的静态变量
-
bss段:保存未初始化的全局变量和静态变量,和初始化为0的静态变量
-
堆:动态内存申请的一段内存空间
-
栈:数据先进后出。内存由系统自动分配,保存函数,参数,局部变量
未完待续。。。。。。