博客
关于我
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/

    你可能感兴趣的文章
    NumPy 库详细介绍-ChatGPT4o作答
    查看>>
    NumPy 或 Pandas:将数组类型保持为整数,同时具有 NaN 值
    查看>>
    numpy 或 scipy 有哪些可能的计算可以返回 NaN?
    查看>>
    numpy 数组 dtype 在 Windows 10 64 位机器中默认为 int32
    查看>>
    numpy 数组与矩阵的乘法理解
    查看>>
    NumPy 数组拼接方法-ChatGPT4o作答
    查看>>
    numpy 用法
    查看>>
    Numpy 科学计算库详解
    查看>>
    Numpy.fft.fft和numpy.fft.fftfreq有什么不同
    查看>>
    numpy.linalg.norm(求范数)
    查看>>
    Numpy.ndarray对象不可调用
    查看>>
    Numpy.VisibleDeproationWarning:从不整齐的嵌套序列创建ndarray
    查看>>
    Numpy:按多个条件过滤行?
    查看>>
    Numpy:条件总和
    查看>>
    numpy、cv2等操作图片基本操作
    查看>>
    numpy中的argsort的用法
    查看>>
    NumPy中的精度:比较数字时的问题
    查看>>
    numpy判断对应位置是否相等,all、any的使用
    查看>>
    Numpy多项式.Polynomial.fit()给出的系数与多项式.Polyfit()不同
    查看>>
    Numpy如何使用np.umprod重写range函数中i的python
    查看>>