当前位置 博文首页 > 李柱明:【linux】系统编程-6-POSIX标准下的信号量与互斥锁

    李柱明:【linux】系统编程-6-POSIX标准下的信号量与互斥锁

    作者:李柱明 时间:2021-01-19 22:07

    目录
    • 前言
    • 8. POSIX信号量
      • 8.1 概念
      • 8.2 POSIX无名信号量
      • 8.3 POSIX有名信号量
      • 8.4 POPSIX信号量与system V信号量的区别
    • 9. POSIX互斥锁
      • 9.1 概念
      • 9.2 初始化互斥锁
      • 9.3 获取互斥锁与释放互斥锁
      • 9.4 销毁互斥锁
    • 参考


    前言

    原文

    8. POSIX信号量

    8.1 概念

    • 信号量(Semaphore)是一种实现进程/线程间通信的机制,可以实现进程/线程之间同步或临界资源的互斥访问, 常用于协助一组相互竞争的进程/线程来访问临界资源。
    • 在POSIX标准中分无名信号量和有名信号量:
      • 无名信号量
        • 一般用于线程间同步或互斥
        • 无名信号量保存于内存中
      • 有名信号量
        • 一般用于进程间同步或互斥
        • 有名信号量保持于文件中
    • 信号量P、V操作
      • P操作(申请资源)
        • 如果有可用资源,则申请成功,信号量减一
        • 如果没有可用资源,则申请失败,进入阻塞或返回
      • V操作(释放资源)
        • 如果信号量的等待队列中有进程/线程在等待,则唤醒一个阻塞的进程/线程
        • 如果没有进程/线程等待阻塞,则信号量加一

    8.2 POSIX无名信号量

    • 无名信号量直接存于内存中,不同进程之间不能互相访问。fork进程中的无名信号量于父进程中的无名信号量是两个独立的信号量。若非要无名信号量用于进程间,则可把信号量放在共享内存中。
    • 包含头文件 #include semaphore.h
    • 相关函数
    int sem_init(sem_t *sem, int pshared, unsigned int value);
    int sem_destroy(sem_t *sem);
    int sem_wait(sem_t *sem);
    int sem_trywait(sem_t *sem);
    int sem_post(sem_t *sem);
    
    • int sem_init(sem_t *sem, int pshared, unsigned int value); :初始化信号量
    • int sem_destroy(sem_t *sem); :销毁信号量
    • int sem_wait(sem_t *sem); :P操作,带阻塞。成功返回0,失败返回-1
    • int sem_trywait(sem_t *sem); :P操作,不阻塞。成功返回0,失败返回EAGAIN
    • int sem_post(sem_t *sem); :V操作。成功返回0,失败返回-1

    8.3 POSIX有名信号量

    • 有名信号量保存于文件中,一般用于进程间同步或互斥。其文件名类似 sem.[信号量名字] ,创建该信号量成功后,系统会将其存放在 /dev/shm
      中。进程退出后,该信号量不会消失,需要手动删除并释放资源。
    • 包含头文件 #include semaphore.h
    • 相关函数
    sem_t *sem_open(const char *name, int oflag, mode_t mode, unsigned int value);
    int sem_wait(sem_t *sem);
    int sem_trywait(sem_t *sem);
    int sem_post(sem_t *sem);
    int sem_close(sem_t *sem);
    int sem_unlink(const char *name);
    
    • sem_t *sem_open(const char *name, int oflag, mode_t mode, unsigned int value); :打开或创建一个有名信号量
    • int sem_wait(sem_t *sem); :P操作,带阻塞。成功返回0,失败返回-1
    • int sem_trywait(sem_t *sem); :P操作,不阻塞。成功返回0,失败返回EAGAIN
    • int sem_post(sem_t *sem); :V操作。成功返回0,失败返回-1
    • int sem_close(sem_t *sem); :关闭信号量,表示当前进程取消对该信号量的使用权。不影响其它进程/线程对其继续使用。
    • int sem_unlink(const char *name); :删除信号量,其它进程/线程也访问不了了。

    8.4 POPSIX信号量与system V信号量的区别

    • 先简单了解一下信号量分类:
      1. 二值信号量:其值为0或为1。
      2. 计数信号量:其值为0至某个限制值(POSIX信号量最大为32767)
      3. 计数信号量集:一个或多个计数信号量构成一个集合。
    • system V信号量所指的是计数信号量集,POSIX信号量所指的是单个计数信号量
    • system V信号量,可以控制每次自增或自减的信号量计数,而POSIX信号量每次只能自增或自减1
    • system V信号量提供的API是没有下划线的:semctl()、semget() 和 semop()
    • system V信号量是内核持续的;POSIX无名信号量是进程持续的;POSIX有名信号量是内核持续

    9. POSIX互斥锁

    9.1 概念

    • 当不同进程/线程去访问某个临界资源的时候,就需要进行互斥保护,这种互斥保护可以看做是一种锁机制。好比上厕所,锁住门,不让别人进。
    • 互斥锁和信号量不同的是,它具有互斥锁所有权、递归访问等特性,常用于实现对临界资源的独占式处理,任意时刻互斥锁的状态只有两种,开锁或闭锁。
      • 互斥锁所有权就是互斥锁被线程持有时,互斥锁处于闭锁状态,线程获得互斥锁的所有权;当该线程释放互斥锁时,该互斥锁处于开锁状态,线程失去该互斥锁的所有权。
      • 互斥锁递归访问,持有该互斥锁的线程具有对该互斥锁进行递归访问。
    • 避免死锁需要遵循的规则
      • 对共享资源操作前一定要获得锁
      • 完成操作后一定要释放锁
      • 尽量短时间占用锁
      • 如果有多锁, 如获得顺序是ABC连环扣, 释放顺序也应该是ABC。
    • 互斥锁比信号量更适合的应用场景:
      • 保护临界资源
      • 线程可能会多次获取互斥锁的情况下。这样可以避免同一线程多次递归持有而造成死锁的问题。
    • 这里的POSIX互斥锁用于线程间

    9.2 初始化互斥锁

    • 包含头文件 #include <pthread.h>
    • 互斥锁静态初始化
      选择以下其一即可
    pthread_mutex_t fastmutex = PTHREAD_MUTEX_INITIALIZER; // 快速互斥锁
    pthread_mutex_t recmutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP; // 递归互斥锁
    pthread_mutex_t errchkmutex = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP; // 检错互斥锁
    
    • 快速互斥锁:具有阻塞机制,不具备递归特性。
    • 递归互斥锁:递归获取互斥锁时,持有互斥锁的计数加1
    • 检错互斥锁:快速互斥锁的非阻塞版本
    • 互斥锁动态初始化
      • mutex 初始化互斥锁结构的指针
      • mutexattr 属性参数,如果该参数为 NULL,则表示选择默认配置,为快速互斥锁。
    int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr);
    

    9.3 获取互斥锁与释放互斥锁

    • 注:非递归互斥锁不具备递归特性。
    • int pthread_mutex_lock(pthread_mutex_t *mutex); :获取互斥锁并上锁,具有阻塞功能
    • int pthread_mutex_lock(pthread_mutex_t *mutex); :获取互斥锁并上锁,不阻塞,发现锁被占用后会返回EBUSY错误
    • int pthread_mutex_unlock(pthread_mutex_t *mutex); :解锁并释放互斥锁

    9.4 销毁互斥锁

    • int pthread_mutex_destroy(pthread_mutex_t *mutex); :销毁互斥锁

    参考

      * 野火
    下一篇:没有了