信号量SytemV与Posix信号量的介绍与用法

目录

1、信号量介绍

2、信号量SystemV介绍

2.1 信号量函数

2.2 信号量C++代码实现

 3、信号量Posix介绍

3.1 无名信号量

3.2 有名信号量


1、信号量介绍

信号量是一种计数器,用在多进程、多线程的共享资源访问控制上面,防止多进程、多线程对共享资源的同时读写。信号量种类有SystemV信号量和Posix信号量。

2、信号量SystemV介绍

信号量SystemV是Linux操作系统的内核对象,由内核同一管理,它的生命周期不依赖创建的进程,即使进程退出,信号量依然存在。信号量SystemV常用于多进程间的同步。最简单的信号信号量是只能取0和1的变量,也叫做二进制信号量,可以去多个正数的信号量被称为通用信号量,本文主要讲解二进制信号量。

2.1 信号量函数

头文件sem.h

(1)semget函数

/*
* @brief: 创建一个新信号量或取得一个已有的信号量。
* @param __key: 信号量标识符,值具有唯一性,不相关进程可以通过它访问一个信号量,常用16进制表示
* @param __nsems: 指定创建信号量数目,常为1,获取已有信号量时值为0.
* @param __semflg:一组标志,它由信号量的访问权限和创建标志组成。
    常用的标志:(1)0640|IPC_CREAT 创建一个新信号量,即使创建的信号量已存在也不会报错;
       (2)0640|IPC_CREAT|IPC_EXCL 创建的新信号量存在时,如果创建的信号量存在,会报错。
* @return int :成功,返回创建成功的信号量标识符;失败:返回-1,并且将errno设置为2
*/
 int semget (key_t __key, int __nsems, int __semflg)

(2)semctl函数

/*
* @brief 用来控制信号量的信息,比如信号量值设置、从系统中删除信号量
* @param __semid:semget函数返回的信号量标识符
* @param __semun:代表给该信号量集中的第几个信号量设置初始值。
* @param __cmd:  信号量操作命令,常用的命令有SETVAL、IPC_RMID
   一般cmd有以下几种:
    IPC_RMID 将信号量集从内存中删除。
    SETVAL   设置信号量集中的一个单独的信号量的值。
    IPC_STAT 读取一个信号量集的数据结构semid_ds,并将其存储在semun中的buf参数中。
    IPC_SET  设置信号量集的数据结构semid_ds中的元素ipc_perm,其值取自semun中的buf参数。
    GETALL   用于读取信号量集中的所有信号量的值。
    GETNCNT  返回正在等待资源的进程数目。
    GETPID   返回最后一个执行semop操作的进程的PID。
    GETVAL   返回信号量集中的一个单个的信号量的值。
    GETZCNT  返回这在等待完全空闲的资源的进程数目。
    SETALL   设置信号量集中的所有的信号量的值。
 @param ...:如果有第四个参数,则该参数格式通常为union semum结构,定义如下:
    union semun
    {    
        int val;    /* Value for SETVAL */通常就要它就够了
        struct semid_ds *buf;    
        unsigned short *arry;    
    };  
        赋值形式:semun.val = 1  //设置信号灯的值为1,表示有一个资源可用
    
*/
int semctl (int __semid, int __semnum, int __cmd, ...)

(3)semop函数

struct sembuf
{
  unsigned short int sem_num;	/* semaphore number */ 信号在信号集中索引,0代表第一个信号
  short int sem_op;		     /* semaphore operation */ 操作类型。 
                                P操作:sem_op = -1,
                                V操作:sem_op = 1                                                   
  short int sem_flg;		/* operation flag */ 操作标志。 通常为SEM_UNDO,使操作系统跟踪信号,                
                                          并在进程没有释放该信号量而终止时,操作系统释放信号量
};

/上面sem_op参数补充//

 sem_op > 0 信号加上 sem_op 的值,表示进程释放控制的资源;
 sem_op = 0 如果没有设置 IPC_NOWAIT,则调用进程进入睡眠状态,直到信号量的值为0;否则进程不会睡 
            眠,直接返回 EAGAIN
 sem_op < 0 信号加上 sem_op 的值。若没有设置 IPC_NOWAIT ,则调用进程阻塞,直到资源可用;否则进 
            程直接返回EAGAIN
///


/*
* @brief:用来改变信号量的值,该函数具有原子性的。
* @param __semid:由semget函数返回的信号量标识符
* @param __sops: 指向由sembuf结构表示的信号量操作数组。
* @param __nspos: 数组元素的个数
* @return int 成功返回0,失败返回-1
*/
int semop (int __semid, struct sembuf *__sops, size_t __nsops)

2.2 信号量C++代码实现

#include 
#include 
#include 
#include 
#include 
#include 

class Semaphore
{
private:
    union semVar
    {
        int val;
        struct semid_ds *buf;
        unsigned short *array;
    };

    int sem_id;
public:
    bool init(key_t key);
    bool wait();
    bool post();
    bool destroy();
};


bool Semaphore::init(key_t key)
{
    sem_id = semget(key,0,0640);
    if(-1 == sem_id)
    {
        if(2 == errno)
        {
            sem_id = semget(key,1,0640|IPC_CREAT);
            if(-1 == sem_id)
            {
                std::cout << "init 1 semget() error" << std::endl;
                return false;
            }else
            {
                union semVar semTmp;
                semTmp.val = 1;
                if(semctl(sem_id,0,SETVAL,semTmp) < 0)
                {
                     std::cout << "init 1 semctl() error" << std::endl;
                     return false;
                }else
                {
                    return true;
                }
            }
        }else
        {
            std::cout << "init 2 semget() error" << std::endl;
            return false;
        }
    }else
    {
        return true;
    }

}


bool Semaphore::wait(){
    struct sembuf sem_b;
    sem_b.sem_num = 0;
    sem_b.sem_op = -1;
    sem_b.sem_flg = SEM_UNDO;
    if(-1 == semop(sem_id,&sem_b,1))
    {
        std::cout << "wait semop failed." << std::endl;
        return false;
    }
    return true;
}

bool Semaphore::post()
{
    struct sembuf sem_b;
    sem_b.sem_num = 0;
    sem_b.sem_op = 1;
    sem_b.sem_flg = SEM_UNDO;
    if(-1 == semop(sem_id,&sem_b,1))
    {
        std::cout << "post semop failed." << std::endl;
        return false;
    }
    return true;
}

bool Semaphore::destroy()
{
    if(semctl(sem_id,0,IPC_RMID) == -1)
    {
        std::cout << "destroy semctl failed." << std::endl;
        return false;
    }
    return true;
}

int main()
{
    Semaphore sem;
    //初始化信号灯
    if(false == sem.init(0x5000))
    {
        std::cout << "sem init failed." << std::endl;
        return -1;
    }
    std::cout << "sem init ok." << std::endl;

    //等待信号灯挂出,等待成功后,将持有锁
    if(false == sem.wait())
    {
        std::cout << "sem wait failed." << std::endl;
        return -1;
    }
    std::cout << "sem wait ok." << std::endl;

    sleep(5);

    //挂出信号灯
    if(false == sem.post())
    {
        std::cout << "sem post failed." << std::endl;
        return -1;
    }
    std::cout << "sem post ok." << std::endl;

    //最后进程结束时,销毁信号灯
    //if(false == sem.destroy())
    //{
    //    std::cout << "sem destroy failed." << std::endl;
    //    return -1;
    //}
    //std::cout << "sem destroy ok." << std::endl;

    return 0;
}

 运行结果如下:

信号量SytemV与Posix信号量的介绍与用法_第1张图片

 3、信号量Posix介绍

Posix是“可移植操作系统接口(Portable Operating System Interface )的首字母简写,但它并不是一个单一的标准,而是一个电气与电子工程学会即IEEE开发的一系列标准,它还是由ISO(国际标准化组织)和IEC(国际电工委员会)采纳的国际标准。Posix信号分为无名信号量和有名信号量。

3.1 无名信号量

Posix的无名信号量一般用于线程同步, 无名信号量是基于用户空间内存的, 它的存续与内存的存续直接相关,无名信号量的api为:sem_init、sem_destroy。

3.2 有名信号量

Posix的有名信号量一般用于进程同步, 它也是由内核统一管理的,因此有名信号量的存续也是由内核决定的,与进程是否退出无关。有名信号量的api为:sem_open、sem_close、sem_unlink。

附加: 

 信号量知识也可参考下面链接:

信号量详解_信号量取值范围怎么求_FangYwang的博客-CSDN博客

信号量--System V信号量 与 Posix信号量-云社区-华为云 (huaweicloud.com)

System V信号量 与 Posix 信号量_分别使用 posix 信号量机制和 system v 信号量机制实现。_luren2015的博客-CSDN博客

SystemV信号量与POSIX信号量简介_执假以为真的博客-CSDN博客

Linux IPC 信号量:PV原语,PV操作,函数semget,函数semop、函数semctl、生产者和消费者模型_linux semop_不会code的菜鸟的博客-CSDN博客 

信号量的操作——semop函数 - 小葫芦藤 - 博客园 (cnblogs.com)

 用信号量为共享内存添加同步机制 - tp_16b - 博客园 (cnblogs.com)

你可能感兴趣的:(C/C++语言,c++)