分享

信号量与自旋锁(3): Linux信号量的实现

 Archangel 2007-08-30
1. 定义:
头文件: <asm/semaphore.h>
数据类型: struct semaphore
直接创建:
void sema_init(struct semaphore *sem, int val); /* 其中val是信号量的初始值 */

辅助宏:
DECLARE_MUTEX(name); /* 把一个称为name的信号量变量初始化为1 */
DECLARE_MUTEX_LOCKED(name); /* 把一个称为name的信号量变量初始化为0 */


动态分配:
/* 用于运行时的初始化 */
void init_MUTEX(struct semaphore *sem);
void init_MUTEX_LOCKED(struct semaphore *sem);


在Linux世界中, P函数被称为down, 指的是该函数减小了信号量的值, 它也许会将调用者置于休眠状态, 然后等待信号量变得可用, 之后再授予调用者对被保护资源的访问权限. down函数有三个版本:
/* 减小信号量的值, 并在必要时一直等待 */
void down(struct semaphore *sem);

/* 可中断版本, 常用 */
void down_interruptible(struct semephore *sem);
作为通常规则, 我们不应该使用非中断版本.
使用该函数, 如果操作被中断, 该函数会返回非0值, 而调用者不会拥有该信号量.
因此对该函数的正确使用需要始终检查返回值, 并做出相应的响应.

/* 永远不会休眠, 如信号量在调用时不可获得, 立即返回非0值 */
void down_trylock(struct semaphore *sem);

当一个线程成功调用down函数的某个版本之后, 就称为该线程拥有了该信号量, 可以访问被该信号量保护的临界区. 当互斥操作完成后, 必须释放该信号量.
Linux的V函数是up:
/* 调用up之后, 调用者不再拥有该信号量 */
void up(struct semaphore *sem);

2. 举例:
我们拥有一个共享数据结构:
struct st_data
{
    char name[32];
    char data[128];
    int data_len;
};

这个数据结构被多个进程同时访问.
为了避免这些进程在访问该结构时产生竞态, 我们在该结构的底部为其加上信号量:
struct st_data
{
    char name[32];              /* name */
    char data[128];              /* data */
    int data_len;                  /* data length */
    struct semaphore sem; /* semaphore */
};

信号量在使用前必须进行初始化, 而且是在共享数据其他部分可用前初始化. 因此, 我们在其他数据赋值之前调用init_MUTEX, 否则会建立一个竞态, 即在信号量准备好之前, 有代码可能会访问它们.

st_data data;
init_MUTEX(&data->sem);
setup_data(&data); /* 初始化数据 */
...
...


接下来, 我们必须仔细检查代码, 确保在不拥有该信号量的时候不会访问data数据结构. 例如, 在data_write的开始处加入:
if (down_interruptible(&data->sem))   
    return -ERESTARTSYS;

这是检查down_interruptible的返回值, 如果返回非0值, 说明操作被中断. 这种情况下, 通常要做的工作是返回-ERESTARTSYS. 在得到这个返回值后, 内核会从头重新启动该调用, 或者将该错误返回给用户.
如果我们返回-ERESTARTSYS, 则必须首先撤销已经做出的修改, 这样, 系统调用才可正确重试. 如果无法撤销这些操作, 则应该返回-EINTR, 表明中断.

不管data_write能否完成其他工作, 它都必须释放信号量:
out:
    up(&data->sem);
    return retval;


在data_write中有几个地方可能会产生错误, 包括内存分配失败等. 在这些情况下, 代码会执行goto out, 确保正确的完成信号量的释放工作.

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

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多