曲径通幽论坛

 找回密码
 立即注册
搜索
查看: 11191|回复: 0
打印 上一主题 下一主题

信号量 | down() | up() | down_trylock() | down_interruptible()

[复制链接]

4918

主题

5880

帖子

3万

积分

GROAD

曲径通幽,安觅芳踪。

Rank: 6Rank: 6

积分
34395
跳转到指定楼层
楼主
发表于 2011-2-21 16:32:15 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
平台:x86 32位
内核:2.6.24

在 linux 中,P 函数被称为 down ;V 函数被称为 up 。

在进入临界区时,用 down 函数对使用计数器减 1,如果成功调用,则该线程就拥有了信号量,从而被赋予访问由该信号量保护的临界区的权力;当信号量计数器为 0 时,其他进程就不能再进入临界区。

down() 函数定义在 include/asm-x86/Semaphore_32.h 中:
static inline void down(struct semaphore * sem)
{
    might_sleep();
    __asm__ __volatile__(
        "# atomic down operation\n\t"
        LOCK_PREFIX "decl %0\n\t"     /* --sem->count */
        "jns 2f\n"
        "\tlea %0,%%eax\n\t"
        "call __down_failed\n"
        "2:"
        :"+m" (sem->count)
        :
        :"memory","ax");
}

decl %0 : %0 表示 sem->count ,这里信号量计数器减 1。
jns 2f : 成功获取信号量。


lea %0, %%eax : 将信号量结构体指针放到 eax 里。这里需要注意的是,结构体的指针(地址)和结构体第一个元素(sem->count)的地址是一样的。
call __down_failed :无法获取信号量时调用 __down_failed 函数处理这种情况,__down_failed 函数的参数用 eax 来传递。


如果用 down() 获取不到信号量时,进程进入睡眠,该进程被放到与该信号量关联的等待队列上。同时,该进程被置为 TASK_UNINTERRUPTIBLE 状态,也就是说处于“非中断”状态,这时候它无法接收信号,这就建立了不可杀进程(ps 命令输出中的 "D state"),这种情况往往让用户感到不爽。


在退出临界区时,必须调用 up() 以释放信号量。该函数的定义为:
static inline void up(struct semaphore * sem)
{
    __asm__ __volatile__(
        "# atomic up operation\n\t"
        LOCK_PREFIX "incl %0\n\t"     /* ++sem->count */
        "jg 1f\n\t"
        "lea %0,%%eax\n\t"
        "call __up_wakeup\n"
        "1:"
        :"+m" (sem->count)
        :
        :"memory","ax");
}

如果 sem->count 为负,那么表明有进程在等待,在加 1 后为 0 ,然后使用函数 __up_wakeup() 函数唤醒因等待信号量而睡眠的某个进程,此后这个进程便可进入临界区,而所有其他仍在等待的进程继续睡眠。


正如上面所说,使用 down() 可能会建立不可杀进程,这会令用户不爽。所以内核还提供了 down_interruptible() 函数,它的工作方式和 down() 相同,它在调用成功时返回 0 值,如果操作被中断则返回非零值。和 down() 不同的是,如果进程无法获得信号量,进程在进入睡眠时是被置为 TASK_INTERRUPTIBLE 状态,这样它可以被信号唤醒。对该函数的正确使用,需要始终检查返回值,并作出相应的响应。


down_trylock() 函数试图获取信号量,如果失败,则进程不会进入睡眠等待信号量,而是继续正常执行。它的定义为:
/*
* Non-blockingly attempt to down() a semaphore.
* Returns zero if we acquired it
*/
static inline int down_trylock(struct semaphore * sem)
{
    int result;

    __asm__ __volatile__(
        "# atomic interruptible down operation\n\t"
        "xorl %0,%0\n\t"
        LOCK_PREFIX "decl %1\n\t"     /* --sem->count */
        "jns 2f\n\t"
        "lea %1,%%eax\n\t"
        "call __down_failed_trylock\n\t"
        "2:\n"
        :"=&a" (result), "+m" (sem->count)
        :
        :"memory");
    return result;
}

从上面的注释也可以看到,如果获取信号量,该函数返回 0 值,否则返回非零值。

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|曲径通幽 ( 琼ICP备11001422号-1|公安备案:46900502000207 )

GMT+8, 2025-5-6 10:19 , Processed in 0.079684 second(s), 23 queries .

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表