1.mmap:
mmap操作提供了一种机制,让用户程序直接访问设备内存,这种机制,相比较在用户空间和内核空间互相拷贝数据,效率更高。在要求高性能的应用中比较常用。mmap映射内存必须是页面大小的整数倍,面向流的设备不能进行mmap,mmap的实现和硬件有关。
mmap()系统调用使得进程之间通过映射同一个普通文件实现共享内存。普通文件被映射到进程地址空间后,进程可以像访问普通内存一样对文件进行访问,不必再调用read(),write()等操作。
2.用户态和内核态
用户空间的应用程序,通过系统调用,进入内核空间,内核代表进程运行于内核空间;
硬件通过触发信号,导致内核调用中断处理程序,进入内核空间,内核代表硬件运行于内核空间;
3.上下文切换
(1)cpu上下文切换:就是先把前一个任务的CPU上下文(也就是CPU寄存器中的数值和程序计数器)保存起来,然后加载新任务的上下文,装载这些寄存器和程序计数器,最后再跳转到程序计数器所指的新位置,运行新任务。而保存下来的上下文,会存储在系统内核中,并在任务重新调度执行的时候再加载进来。这样就能保证任务原来的状态不受影响,让任务看起来还是连续运行。
(2)系统调用上下文切换:系统调用时也存在上下文切换(系统调用过程通常称为特权模式切换,而不是上下文切换。但实际上,系统调用过程中,CPU 的上下文切换还是无法避免)。
(3)进程上下文切换:进程的上下文不仅包括了进程虚拟内存、栈、全局变量等用户空间的资源,还包括了内核堆栈、cpu寄存器等内核空间的状态。
(4)线程上下文切换
(5)中断上下文切换(当发生硬件中断时,会陷入内核态执行中断服务程序)
https://www.cnblogs.com/zhuangquan/p/16825697.html
内核同步机制:
原子操作:原子操作需要硬件的支持,因此是架构相关的,其API和原子类型的定义都定义在内核源码树的include/asm/atomic.h文件中,它们都使用汇编语言实现,因为C语言并不能实现这样的操作。原子操作主要用于实现资源计数,很多引用计数(refcnt)就是通过原子操作实现的。
自旋锁:自旋锁在内核中主要用来防止多处理器中并发访问临界区,防止内核抢占造成的竞争。可用于进程上下文和中断上下文。自旋锁可以在任何时刻防止多于一个的内核任务同时进入临界区,因此这种锁可有效地避免多处理器上并发运行的内核任务竞争共享资源。
如果spin_lock不处于中断上下文,则spin_lock锁定的代码只会在内核发生抢占的时候才会丢失CPU拥有权。所以,对于单核来说,需要在spin_lock获得锁的时候禁止抢占,释放锁的时候开放抢占。也就是单核cpu上持有自旋锁的时候不允许调度,否则容易引起死锁。
信号量:只能用在进程上下文,不能用于中断上下文(因为中断上下文不能被调度,所以不能休眠,因为如果等待锁休眠后,就无法再次被调度起来执行)。
等待自旋锁不会引起任务休眠(耗cpu时间),所以适用于短期轻量级资源保护,互斥量会休眠可以满足较长时间保护资源的需求。
另外,信号量不同于自旋锁,它不会关闭内核抢占,所以持有信号量的代码可以被抢占。这意味者信号量不会对影响调度反应时间带来负面影响。spin lock关闭内核抢占(linux的kernel的特性,在某一进程获取spin lock的时候,禁止本CPU上的其它任务抢占,避免发生死锁,比如线程A持有锁的时候被中断执行,中断触发了高优先级的进程B在本cpu上开始执行,B需要获取spin lock的时候就会死等出现死锁)
自死琐是说自己占有了某个资源,然后 自己又申请自己已占有的资源。自己等待自己。
当发生访问资源冲突的时候,可以有两个选择:一个是死等,一个是挂起当前进程,调度其他进程执行。spin lock是一种死等的机制,当前的执行thread会不断的重新尝试直到获取锁进入临界区。如果自旋锁持有的时间长的话,那么等待这个锁的任务都在自旋等待,浪费cpu。