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

    你可能感兴趣的文章
    opencv——图像缩放1(resize)
    查看>>
    opencv——最简单的视频读取
    查看>>
    Opencv——模块介绍
    查看>>
    OpenCV与AI深度学习 | 2024年AI初学者需要掌握的热门技能有哪些?
    查看>>
    OpenCV与AI深度学习 | CIB-SE-YOLOv8: 优化的YOLOv8, 用于施工现场的安全设备实时检测 !
    查看>>
    OpenCV与AI深度学习 | CoTracker3:用于卓越点跟踪的最新 AI 模型
    查看>>
    OpenCV与AI深度学习 | OpenCV中八种不同的目标追踪算法
    查看>>
    OpenCV与AI深度学习 | OpenCV图像拼接--Stitching detailed使用与参数介绍
    查看>>
    OpenCV与AI深度学习 | OpenCV如何读取仪表中的指针刻度
    查看>>
    OpenCV与AI深度学习 | OpenCV常用图像拼接方法(一) :直接拼接
    查看>>
    OpenCV与AI深度学习 | OpenCV常用图像拼接方法(三):基于特征匹配拼接
    查看>>
    OpenCV与AI深度学习 | OpenCV常用图像拼接方法(二) :基于模板匹配拼接
    查看>>
    OpenCV与AI深度学习 | OpenCV常用图像拼接方法(四):基于Stitcher类拼接
    查看>>
    OpenCV与AI深度学习 | OpenCV快速傅里叶变换(FFT)用于图像和视频流的模糊检测(建议收藏!)
    查看>>
    OpenCV与AI深度学习 | PaddleOCR 2.9 发布, 正式开源文本图像智能分析利器
    查看>>
    OpenCV与AI深度学习 | SAM2(Segment Anything Model 2)新一代分割一切大模型介绍与使用(步骤 + 代码)
    查看>>
    OpenCV与AI深度学习 | T-Rex Label !超震撼 AI 自动标注工具,开箱即用、检测一切
    查看>>
    OpenCV与AI深度学习 | YOLO11介绍及五大任务推理演示(目标检测,图像分割,图像分类,姿态检测,带方向目标检测)
    查看>>
    OpenCV与AI深度学习 | YOLOv10在PyTorch和OpenVINO中推理对比
    查看>>
    OpenCV与AI深度学习 | YOLOv11来了:将重新定义AI的可能性
    查看>>