博客
关于我
Linux并发与同步专题 (3) 信号量
阅读量:674 次
发布时间:2019-03-16

本文共 2429 字,大约阅读时间需要 8 分钟。

信号量(Semaphore)是操作系统中常用的同步机制,用于管理进程间的互斥和同步问题。本文将深入探讨信号量的实现原理、初始化方法以及常见的down()/up()操作函数。

信号量数据结构

信号量由struct semaphore结构体描述,主要成员包括:

  • spinlock_t lock:用于保护信号量中的count和wait_list成员,spinlock是一种EncodingException,允许在持锁状态下进行短时间内_Draw的操作。
  • unsigned int count:表示允许进入临界区的内核执行路径个数。
  • list_head wait_list:用于管理所有在该信号量上睡眠的进程,未成功获取锁的进程会在这个链表上等待。
  • 信号量还定义了一个与其相关的struct semaphore_waiter结构体,该结构体用于描述等待信号量的进程:

    • list_head list:表示该进程在信号量的等待队列中的位置。
    • task_struct task*:指向等待信号量的进程结构。
    • bool up:标记该进程是否需要被唤醒。

    信号量的初始化

    信号量的初始化分为两种:动态初始化和静态定义。两种方式均通过__SEMAPHORE_INITIALIZER()初始化相关成员变量。

    #define __SEMAPHORE_INITIALIZER(name, n) {    .lock        = __RAW_SPIN_LOCK_UNLOCKED((name).lock),    .count        = n,    .wait_list    = LIST_HEAD_INIT((name).wait_list),}#define DEFINE_SEMAPHORE(name)    struct semaphore name = __SEMAPHORE_INITIALIZER(name, 1)static inline void sema_init(struct semaphore *sem, int val) {    static struct lock_class_key __key;    *sem = (struct semaphore) __SEMAPHORE_INITIALIZER(*sem, val);    lockdep_init_map(&sem->lock.dep_map, "semaphore->lock", &__key, 0);}

    down()/up()

    信号量的使用基础上,down()/up()函数对信号量的加锁和解锁操作起着关键作用。

    down()的实现主要包括以下步骤:

    void down(struct semaphore *sem) {    unsigned long flags;    raw_spin_lock_irqsave(&sem->lock, flags);    if (likely(sem->count > 0)) {        sem->count--;    } else {        __down(sem);    }    raw_spin_unlock_irqrestore(&sem->lock, flags);}

    当信号量.count大于0时,本地加锁并减少count值,表示当前进程已获得信号量。否则,调用__down()进入等待队列。

    __down()函数会根据不同的 errno类型调用__down_common(),参数state决定进程进入哪种睡眠状态:

    • TASK_UNINTERRUPTIBLE:在不可中断睡眠,直到信号量被唤醒。
    • TASK_INTERRUPTIBLE或TASK_KILLABLE:进入可中断或不可中断但可杀死的睡眠等待。

    down_interruptible()与down()类似,但进程进入可中断睡眠状态。

    down_killable()允许进程在不可中断状态下被唤醒。

    down_timeout()是在超时后唤醒的特定实现。

    down_trylock()尝试获取锁但不阻塞。

    int down_trylock(struct semaphore *sem) {    unsigned long flags;    int count;    raw_spin_lock_irqsave(&sem->lock, flags);    count = sem->count - 1;    if (likely(count >= 0)) {        sem->count = count;    }    raw_spin_unlock_irqrestore(&sem->lock, flags);    return (count < 0);}

    up()函数的实现相对简单:

    void up(struct semaphore *sem) {    unsigned long flags;    raw_spin_lock_irqsave(&sem->lock, flags);    if (list_empty(&sem->wait_list)) {        sem->count++;    } else {        __up(sem);    }    raw_spin_unlock_irqrestore(&sem->lock, flags);}

    信号量与spinlock的对比

    spinlock和信号量都是同步机制,但主要区别如下:

    • spinlock:不允许进程在加锁期间进入睡眠,采用忙等待策略。同一时刻只能被一个内核代码路径持有,最适用于快速完成的临界区保护。
    • 信号量:允许进程在加锁失败时进入睡眠状态。同一时刻可以由多个进程持有,最适用于加锁时间较长或需要等待的场景。

    转载地址:http://fpoqz.baihongyu.com/

    你可能感兴趣的文章
    Python 子进程 Popen.communicate() 等价于 Popen.stdout.read()?
    查看>>
    Python 子进程 Popen:为什么会出现“ls *.txt“?不行?
    查看>>
    Python 子进程参数
    查看>>
    python 字典 key 和value 互换
    查看>>
    Python 字典 vs If 语句速度
    查看>>
    python 字典sorted自定义排序,按照key or value排序
    查看>>
    python 字典和列表区别_元组列表和字典的主要区别是什么?
    查看>>
    python 字符串中特定字符替换,截取
    查看>>
    Python 字符串总结
    查看>>
    python 字符串显示中文_Python字符串开头的b"、u"、r"与中文乱码
    查看>>
    Python 字符串的几种拼装方式
    查看>>
    python 存入数据库bigint_python基础_MySQL的bigint类型
    查看>>
    python 学习 面向对象编程
    查看>>
    Python 学习小结
    查看>>
    Python 学习日记第三篇 -- 字典
    查看>>
    Python 学习笔记(一)Data type
    查看>>
    python 安装 easy_install 和 pip 流程
    查看>>
    python 安装echarts
    查看>>
    python 安装opencv及问题解决
    查看>>
    Python 安装程序:“写入文件 C:\Python27\pythonw.exe 时出错“
    查看>>