Chinaunix首页 | 论坛 | 博客
  • 博客访问: 22459
  • 博文数量: 8
  • 博客积分: 20
  • 博客等级: 民兵
  • 技术积分: 149
  • 用 户 组: 普通用户
  • 注册时间: 2010-06-01 11:02
个人简介

no no no

文章分类

全部博文(8)

文章存档

2013年(8)

我的朋友

分类: LINUX

2013-06-28 23:21:51

1. 之前的问题

点击(此处)折叠或打开

  1. if (!dptr->data[s_pos]) {
  2.     dptr->data[s_pos] = kmalloc(quantum, GFP_KERNEL);
  3.     if (!dptr->data[s_pos])
  4.         goto out;
  5. }
这里如果两个进程同时走到kmalloc则会有问题。kmalloc之前进程切换,则会导致某个进程调用时内核内存泄漏。所以要并发控制


2. 信号量、互斥锁
即理论上的P V操作,内核封装了一层作为互斥锁(概念上默认是睡眠的)。以下三个版本区别如下:
void down(struct semaphore *sem);   这个一直等待。不可中断,是建立“非可杀进程”的手段
int down_interruptible(struct semaphore *sem);    也一直等待,但是可中断。
int down_trylock(struct semaphore *sem);    这个则不睡眠


另一种是读写类型的信号量,实现成读写类的互斥锁。这种互斥锁的问题是写者多时,读的执行线程会饥饿。
这里的执行线程不是线程,而是指可能执行到它的代码流。既包括用户空间调进来的,也包含正常的中断等。


一个执行线程等待另一个执行线程完成一些工作时,一般不用互斥锁,而是可用completion接口。


3. 自旋锁
即忙等,它最初是用于多处理器上的。而在单处理下,内核抢占的行为就类似于SMP。


优点:1.它广泛用于不可休眠的代码中,如中断处理中;2.正确使用时,性能比信号量更好。


非内核抢占单处理器上的内核代码进入自旋状态,则会永远自旋。


自旋锁使用原则:拥有锁的代码必须是原子的,原子的意思是不可以睡眠,不可以中断:
睡眠会如何:如果拥有自旋锁的代码睡眠,则会造成其他执行线程取锁忙等,性能差;解决方法是一般拥有自旋锁则禁止内核抢占;
中断会如何:如果取到自旋锁的代码被中断,假如中断处理试图再取此锁,则死锁。解决方法是在自旋锁获取的同时禁止当前cpu中断。


void spin_lock(spinlock_t *lock);


以下二个用于可能在中断处理中取得的自旋锁,如上述,它取得锁后禁中断。
void spin_lock_irqsave(spinlock_t *lock, unsigned long flags);
void spin_lock_irq(spinlock_t *lock);     


以下用于可能在中断下半部取得自旋锁的代码,如取得则禁软中断。
void spin_lock_bh(spinlock_t *lock)


4. 锁的注意
死锁防止:
1. 单锁:单锁死锁最可能的是获取锁的代码去调用某函数,而这函数中又试图取锁。无论互斥锁还是自旋锁,都死锁;
2. 多锁:理论上的方法是取锁顺序一致,但这方法不可操作;
        实践性强的如下:先取局部锁,后取大锁; 有互斥锁(信号量)与自旋锁同时存在时,一定先取互斥锁,否则自旋锁睡眠。
最好防止需要多锁的情况。


粒度:
2.0最初是大内核锁,慢慢优化到如今。


设计锁的规则:最初使用大粒度锁,除非真正发现锁竞争会导致问题再尝试细化。因为真正的性能瓶颈往往出现在非预期的情况。


5. 非锁处理方法
循环缓冲区:生产消费者模型;原子变量、内核位操作:cpu硬件级锁;
seqlock、rcu等高级货。













阅读(475) | 评论(0) | 转发(0) |
0

上一篇:ldd ch4

下一篇:01 从某字符串中移除数字

给主人留下些什么吧!~~