分享

信号量和互斥锁

 champion_xu 2012-06-07
信号量与互斥锁都是保护临界数据的常用手段。这里先了解几个概念。
执行线程:thread of execution,指任何正在执行的代码实例,可能是一个正在内核线程,一个中断处理程序等。有时候会将执行线程简称为线程。
临界区:critical region,即访问和操作共享数据的代码段。
多个执行线程并发访问同一资源通常是不安全的,通常使用自旋锁和信号量来实现对临界区互斥的访问。

信号量:
信号量其实就是一个整数值,通常有对应的一对操作,即P和V。其中P操作是获得信号量,此时要将信号量值减1,如果信号量大于0则正常获取信号量,但是如果信号量值小于等于0,则进程阻塞休眠,等待其他占用信号量的进程释放信号量。自然V操作就对应着释放信号量,信号量加值1,并在必要时候唤醒休眠进程。

信号量数据结构:
struct semaphore {
    spinlock_t        lock;
    unsigned int        count;
    struct list_head    wait_list;
};
其中wait_list是等待信号量的进程列表。lock为自旋锁(后面介绍)。count为信号量值。

信号量的初始化:
方法1(静态法):
DEFINE_SEMAPHORE(lock); //在新的内核中直接用semaphore
此时信号量值被初始化为1,即互斥量。效果等同于DECLARE_MUTEX(name);
具体函数情况如下:
#define DEFINE_SEMAPHORE(name)    \
    struct semaphore name = __SEMAPHORE_INITIALIZER(name, 1) //此处信号量结构体没有定义为指针
#define __SEMAPHORE_INITIALIZER(name, n)                \
{                                    \
    .lock        = __SPIN_LOCK_UNLOCKED((name).lock),        \
    .count        = n,                        \
    .wait_list    = LIST_HEAD_INIT((name).wait_list),        \
}
方法2(动态法):
struct semaphore sem;
void sema_init(&sem,val);
val为初始化信号量的值。

获取信号量:
void down(struct semaphore *name);
int down_interruptible(struct semaphore *name);//操作被中断返回非0值
int down_trylock(struct semaphore *name);//若不可获得则返回0
建议使用interruptible版本,其中down_trylock版本不会导致休眠,一般在非阻塞进程中使用。
释放信号量:
void up(struct semaphore *name);

自旋锁:
自旋锁定义很简单,只有2个值,即锁定和解锁。事实上自旋锁的应用在内核中往往比信号量更多,更常见。在正确使用下自旋锁常常可以提供比信号量更高的性能。但是拥有自旋锁时不能休眠,这样可能导致死锁等很多不可预料的情况。同时自旋锁的一个好处是可以在中断中使用,而信号量不可用,因为信号量会导致进程休眠,如果在中断中导致休眠,则也可能导致无法释放信号量,而导致很多不可预料的结果。
当自旋锁被占用而有人需要去获得时,代码就会进入自旋状态,不断的忙循环检查锁的可用状态,因为自旋锁本质上都是不可中断的。此时执行忙循环的处理器做不了任何有用的工作,这也警示了我们需要正确使用自旋锁,拥有锁的时间要尽量短,代码尽量少,以避免出现不必要的BUG,甚至需要restart。

自旋锁的初始化:
方法1:
spinlock_t mylock = SPIN_LOCK_UNLOCKED;
方法2:
在init函数或者其他函数中使用函数->
void spin_lock_init(spinlock_t  *lock);

自旋锁锁定:
void spin_lock(spinlock_t  *lock);
void spin_lock_irqsave(spinlock_t  *lock, unsigned long flags);//在本处理器上禁止所有中断并保存在flags中
void spin_lock_irq(spinlock_t  *lock);//禁止中断而不保存,这需要我们确认没有其他代码禁止中断,而释放锁时可以立即启用中断
void spin_lockbh(spinlock_t  *lock);//禁止软中断,但是会打开硬件中断

释放自旋锁:
void spin_unlock(spinlock_t  *lock);//对应上述第1个锁定
void spin_unlock_irqrestore(spinlock_t  *lock, unsigned long flags);//对应上述第2个锁定
void spin_unlock_irq(spinlock_t  *lock);//对应上述第3个锁定
void spin_unlock_bh(spinlock_t  *lock);//对应上述第4个锁定

另外有非阻塞版的自旋锁操作:
int spin_trylock(spinlock_t  *lock);
int spin_trylock_bh(spinlock_t  *lock);
成功将返回非0值,失败返回0。





    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多