目录

高大上的技术

Double Checked Locking,双重检测锁,DCL

我们知道加锁的代价是昂贵的,因为加锁了才能检查,那为何不在加锁前检查一次呢,如果存在,都不需要走到带锁代码,这样即安全,又提高了性能,唯一的缺点就是检查了 2 次。

内存可见性

指令重排序

busy-waiting 忙等待

进程/线程执行到一段循环程序的时候,由于循环判断条件不能满足而导致处理器反复循环,处于繁忙状态,该进程/线程虽然繁忙但无法前进。

重入Reentrant

为什么中断处理函数不能直接调用不可重入函数?

在多任务系统下,中断可能在任务执行的任何时间发生;如果一个函数的执行期间被中断后,到重新恢复到断点进行执行的过程中,函数所依赖的环境没有发生改变,那么这个函数就是可重入的,否则就不可重入。

在中断前后不都要保存和恢复上下文吗,怎么会出现函数所依赖的环境发生改变了呢?我们知道中断时确实保存一些上下文,但是仅限于返回地址,cpu 寄存器等之类的少量上下文,而函数内部使用的诸如全局或静态变量,buffer 等并不在保护之列,所以如果这些值在函数被中断期间发生了改变,那么当函数回到断点继续执行时,其结果就不可预料了。

在中断处理函数中调用有互斥锁保护的全局变量,如果恰好该变量正在被另一个线程调用,会导致中断处理函数不能及时返回,导致中断丢失等严重问题。

并且在多线程环境中使用,在没有加锁的情况下,对同一段内存块进行并发读写,就会造成 segmentfault/coredump 之类的问题。

总而言之,中断处理函数做的事情越简单越好。

如何解决缓存一致性

我们的程序太快,如果直接与数据库交互,数据库太慢,CPU 总是在等待,不要说什么多线程,IO 太慢时,线程频繁调度也没用。 为了解决上述问题,在程序和数据库中间加上缓存,那么又来了新的问题,更新数据时存在,存在数据不一致问题。

大咖秀

现代 CPU 中,如果 CPU 直接与内存交互,则存在内存速度太慢,CPU 太快总是在等待的问题。即内存拉低了 CPU 的效率。 为了解决上述问题,在 CPU 与内存之间加入很多寄存器,和多级缓存。可是这样又引发了新的问题。 由于 CPU 与内存之间加入了缓存,在进行数据操作时,先将数据从内存拷贝到缓存中,CPU 直接操作的是缓存中的数据。但在多处理器下,将可能导致各自的缓存数据不一致(这也是可见性问题的由来),为了保证各个处理器的缓存是一致的,就要实现==缓存一致性协议==,而==嗅探==是实现缓存一致性的常见机制。

OOD

OOD 是一种解决软件问题的设计范式(paradigm),一种抽象的范式。 使用 OOD 这种设计范式,我们可以用对象(object)来表现问题领域(problem domain)的实体,每个对象都有相应的状态和行为。

自旋和挂起

自旋也叫忙等(busy-wait),采用这种方式的线程不会被挂起,而是会消耗一定的 CPU 资源去循环 check 是否可以执行了。 挂起就是把你从 CPU 的使用中换出,当可用的时候再让你运行。这种换进换出叫着上下文切换,上下文是需要 CPU 调度开销的,一般是相当于 5000~10000 个时钟周期,对于主频为 1GHz 的 CPU 来说,也就是需要 1 到 2 个微秒。

大概的意思是,如果自旋开销小于上下文切换开销,则推荐使用自旋,反之使用挂起。也就是说如果竞争不激励,自旋高效;竞争激励,线程等待时间长,挂起更高效。同样的道理同样适用其它领域:交通信号灯在拥堵的交通状况下能带来更好的吞吐量,但是环岛在低拥堵的情况下能够带来更好的吞吐量。

———————————————— 版权声明:本文为CSDN博主「张建飞(Frank)」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/significantfrank/article/details/80399179