linux锁学习记录

临界区和竞争条件:

       所谓的临界区,就是访问和操作共享数据的额代码段,多个执行线程并发访问同一个资源通常是不安全的。为了避免在临界区中并发的执行,必须保证这些代码原子的执行。如果两个执行线程有可能处于同一临界区中同事执行,那么这就是程序的bug,如果情况真的发生,就称之为竞争条件。这种情况出现的机会往往非常小。

       这样,避免并发和防止竞争条件成为同步。

       锁是采用原子操作实现的,而原子操作不存在竞争,

造成并发执行的原因

       用户空间之所以需要同步,是因为用户程序会被调度程序抢占和重新调度。由于用户进程可能在任何时刻被抢占,而调度程序完全可能选择另一个高优先级的进程到处理器上执行,所以就会使得一个程序正在处于临界区时,被非自愿的抢占了。如果重新调度的进程随后也进入同一个临界区,前后两个进程相互之间就会产生竞争。另外,因为信号处理是异步发生的,所以,即使是单线程的多个进程共享文件,或者在一个程序内部处理信号,也有可能产生竞争条件。

       内核中有类似可能造成并发执行的原因。

       中断——几乎可以在任何时刻异步,打断当前正在执行的代码。

       软中断和tasklet——内核能在任何时刻唤醒或者重新调度软中断和tasklet。打断当前正在执行的代码

       内核抢占——内核具有抢占性。

       睡眠以及与用户空间同步。

       对称多处理——两个或多个处理器其可以同时执行代码

因此存在如下的bug:

       如果在一段内核代码操作某一资源的时候系统产生了一个中断,而且该中断的处理程序还要访问这一资源,这就是一个bug.

       如果一段内核代码在访问一个共享资源期间可以被抢占,这也是一个bug.

       如果内核代码在临界区里睡眠,那简直就是故障欢迎竞争条件的

实际上,真正有挑战性的地方在于辨认出真正需要共享的数据和相应的临界区,记住,在开始设计代码的时候就要考虑加入锁。

       在编写代码的开始阶段就要设计恰当的锁。

重要的是了解需要保护写什么。

       对于大对数的内核数据来说都是需要加锁的。如果有其他执行线程可以访问这些数据,那么这些数据就要加上某种形式的锁。切记,是要给数据枷锁而不是要给代码加锁。

       在编写内核代码的同时,需要考虑如下的问题:

       这个数据是不是全局的,除了当前进线程以外,其他线程能不能访问他。

       这个数据会不会在进程上下文和中断上下文中共享。

       进程在访问数据时可不可能被抢占,被调度的程序会不会访问同一数据

       当前进程是不是会睡眠在某些资源上,如果会的话,此时的数据处于何种状态

       如何防止数据失控

       如果函数在另一个处理器上被调度还会怎么样

       如何确保代码远离并发的威胁?

死锁

       死锁的产生需要一定的条件,要有一个或多个执行的线程和一个或多个资源。每个线程都在等待其中的一个资源,但是所有的资源都已将被占用。线程之间相互等待。但他们永远不会释放已经占有的资源。

可以用一些简单的规则来帮助避免死锁

       使用嵌套的锁时必须保证以相同的顺序获取锁,这样可以阻止致命拥抱类型的锁。

       防止发生饥饿。

       不要重复请求同一个锁

       设计应力求简单。

在代码中使用锁的地方,对锁的获取顺序加上顺序是个良好的习惯。

争用和扩展性:

       锁的争用会降低系统的性能,高度争用的锁会成为系统的瓶颈。

       扩展性是对系统可扩展程度的一个量度。

 

       在设计之初加锁方案应该力求简单,仅当需要时再进一步细化方案

精髓在于力求简单。

       记录就到这里

 

       爱你YZ

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值