• Linux 信号量详解一


         信号量主要用于进程间(不是线程)的互斥,通过sem_p()函数加锁使用资源,sem_v函数解锁释放资源,在加锁期间,CPU从硬件级别关闭中断,防止pv操作被打断。
    semget函数
    int semget(key_t key, int nsems, int semflg);
    --功能:用来创建和访问一个信号量集
    --参数
        key:信号集的key值
        nsems:信号集中信号量的个数
        semflg:由九个权限标志构成,他们的用法和创建文件时使用的mode模式标志是一样的
    --返回值:成功返回一个非负整数,即该信号集的标识码,失败返回-1,并且更新errno
    shmctl函数
    int semctl(int semid, int semnum, int cmd, ...);
    --功能:用于控制信号量集
    --参数
        semid:由semget返回的信号集标识码
        semnum:信号集中信号量的序号(信号量的序号从0开始,和数组类似)
        cmd:将要采取的动作(有5个可取值)
        最后一个参数根据命令不同而不同
    --返回值:成功返回0;失败返回-1并且更新errno
    semop函数
    int semop(int semid, struct sembuf *sops, unsigned nsops);
    --功能:
    --参数
        semid:semget函数的返回值
        sops:是个指向一个结构体的指针
        nsops:信号量的个数
    --返回值:成功返回0,失败返回-1,并且更新errno
    semop函数续
    --sembuf结构体
    struct sembuf
    {
        unsigned short sem_num; /* semaphore number */
        short sem_op; /* semaphore operation */
        short sem_flg; /* operation flags */
    };
    sem_num是信号量的编号
    sem_op是信号量一次PV操作是加减的数值,一般只会用到两个值,一个是"-1",也就是P操作,等待信号量变得可用;另一个是"+1",也就是V操作,发出信号量已经变得可用。
    sem_flg的两个取值IPC_NOWAIT或SEM_UNDO,SEM_UNDO是进程完成P操作后直接被终止了,那么系统会自动执行V操作,恢复成默认值
    //信号量API
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <errno.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/ipc.h>
    #include <sys/sem.h>
    
    //这个定义不可少
    union semun
    {
        int val;    // Value for SETVAL
        struct semid_ds *buf;    // Buffer for IPC_STAT, IPC_SET
        unsigned short *array;  // Array for GETALL, SETALL
        struct seminfo *__buf;  // Buffer for IPC_INFO(Linux-specific)
    };
    
    /**
     * sem_setval - 设置信号量的资源值
     * semid:由semget返回的信号集标识码
     * val:资源值
     * 成功返回0,失败返回-1
     * */
    int sem_setval(int semid, int val)
    {
        int ret = 0;
        //union semun必须自定义
        union semun su;
        su.val = val;
        //semctl()第二个参数是序号,这里取第一个信号量
        ret = semctl(semid, 0, SETVAL, su);
        if (ret == -1)
        {
            perror("semctl() err");
        }
        return ret;
    }
    
    /**
     * sem_setval - 获取信号量的资源值
     * semid:由semget返回的信号集标识码
     * 成功返回可用资源值,失败返回-1
     * */
    int sem_getval(int semid)
    {
        int ret = 0;
        //semctl()第二个参数是序号,这里取第一个信号量
        //当使用GETVAL命令时,调用中的最后一个参数被忽略
        //成功返回该信号量的可用资源值
        ret = semctl(semid, 0, GETVAL, 0);
        if (ret == -1)
        {
            perror("semctl() err");
        }
        printf("getval=%d
    ", ret);
        return ret;
    }
    
    /**
     * sem_p - 信号量P操作
     * semid:由semget返回的信号集标识码
     * 成功返回0,失败返回-1
     * */
    int sem_p(int semid)
    {
        int ret=0;
        //通过struct sembuf结构体的sem_op属性设置P操作
        //sem_flg默认设置为0
        struct sembuf sbuf={0,-1,0};
        ret=semop(semid,&sbuf,1);
        if(ret==-1)
            perror("semop() err");
        return ret;
    }
    
    /**
     * sem_v - 信号量V操作
     * semid:由semget返回的信号集标识码
     * 成功返回0,失败返回-1
     * */
    int sem_v(int semid)
    {
        int ret=0;
        //通过struct sembuf结构体的sem_op属性设置P操作
        //sem_flg默认设置为0
        struct sembuf sbuf={0,1,0};
        ret=semop(semid,&sbuf,1);
        if(ret==-1)
            perror("semop() err");
        return ret;
    }
    
    int main()
    {
        //创建或者访问信号量集
        int semid = 0;
        //第二个参数创建几个信号量
        semid = semget(0x1234, 1, 0666 | IPC_CREAT | IPC_EXCL);
        if (semid == -1)
        {
            if (errno == EEXIST)
            {
                printf("该信号量集已经存在!
    ");
                semid = semget(0x1234, 1, 0666);
            } else
            {
                perror("semget() err");
                return -1;
            }
        }
        //设置第0个信号量的s(可用资源)的值为1
        sem_setval(semid, 1);
        sem_getval(semid);
        sem_p(semid);
        printf("dddddd
    ");
        sem_v(semid);
        return 0;
    }
  • 相关阅读:
    JMETER接口测试问题三之Host of origin may not be blank
    JMETER接口测试问题解决二之后续接口请求依赖登录接口的操作
    JMETER接口测试问题一之请求超时报错
    jmeter接口测试之json提取器的使用方法二
    JMETER接口测试之Debug sample
    JMTER接口测试之JSON提取器
    EXCEL批量导入到Sqlserver数据库并进行两表间数据的批量修改
    Linq的整型或实体类null引发的报错问题
    SqlServer 统计1-12月份 每个月的数据(临时表)
    select2的多选下拉框上传
  • 原文地址:https://www.cnblogs.com/zhanggaofeng/p/6224269.html
Copyright © 2020-2023  润新知