SystemV 信号量 以及 SEM_UNDO 说明

版权声明: https://blog.csdn.net/dashoumeixi/article/details/84627088

SysV 信号量集  : 一个信号量数组;  命令 ipcs - s 查看

//这个联合体 有些linux系统中没定义. 其实可用可不用 
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) */
};

semget : 创建或获取一个信号量集 . 第2个参数, 指定N个信号量;

semop:  修改一个或一批信号量. 相当于 posix 中的 sem_wait  和 sem_post 综合体

              每个信号量由struct sembuf 控制. 

              sem_num 表示第N个信号量. 

              sem_op 可以是 > 0 , 0 , <0 , 相当于  sem_post == 1, sem_wait ==  -1;

              sem_flg : IPC_NOWAIT  不阻塞, SEM_UNDO 还原;

sem_ctl : 给信号量赋值, 删除, 状态等

SEM_UNDO: 如果指定了. 不论当前进程是否正常退出 都将还原此操作的 sem_op 值. 用于以防万一异常结束的进程

如果是生产者/消费者的情况,则不应该使用

比如:

if(0== fork()){
    struct sembuf sem;
    sem.sem_num = 0;
    sem.sem_op = -1;
    sem.sem_flg = SEM_UNDO;
    semop(semid,&sem,1)

/*
    一般正常的还原操作;  如果指定了SEM_UNDO 则不写也没关系.子进程结束后将还原;
    sem.sem_op = 1;
    semop(semid,&sem,1);
*/
exit(0);
}
当这段代码执行完后. 由于SEM_UNDO,进程被回收前 相当于将执行 被注释的代码;
SEM_UNDO 用于以防万一,异常结束的进程;

semcreate.c

#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/types.h>
#include <stdlib.h>
#include <time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>

int main(int argc ,char** argv ,char ** env)
{
    if(argc != 3){
        puts("pathname nsems");
        return 0;
    }

    int nsems = atoi(argv[2]);
    int key = ftok(argv[1],0);

    //创建一个信号量集 , 包含 nsems 个信号量
    int semid = semget(key,nsems,IPC_CREAT|0644);
    printf("nsems:%d , key:%d,semid:%d\n", nsems, key,semid);


    return 0;
}

semsetvalue.c

#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/types.h>
#include <stdlib.h>
#include <time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>

int main(int argc ,char** argv ,char ** env)
{
    if(argc < 2){
        puts("pathname semvalues[max nsems]");
        return 0;
    }
    //获取信号量集
    int semid = semget(ftok(argv[1],0),0,0);
    printf("semid:%d\n" , semid);

    struct semid_ds semstat = {0};
    //获取信号量状态
    semctl(semid,0,IPC_STAT,&semstat);

    //信号量个数
    int nsems = semstat.sem_nsems;
    printf("nsems  : %d\n" , nsems);

    //分配内存给信号量赋值
    unsigned short * ptr = calloc(nsems,sizeof(unsigned short));

    for(int i =0 ; i < nsems; ++i)
        ptr[i]= atoi(argv[i+2]);

    // SETALL 一起赋值 , SETVAL 单个赋值
    if(semctl(semid,0,SETALL,ptr) < 0)
        perror("set values failed");
    else
        puts("set values success");

    return 0;
}

semgetvalue.c

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>


int main(int argc ,char** argv ,char ** env)
{
    if(argc != 2){
        puts("pathname");
        return 0;
    }
    int key = ftok(argv[1],0);

    // 获取
    int semid = semget(key,0,0);
    printf("semid:%d\n" , semid);

    struct semid_ds semidbuf = {0};

    //获取信号量数量
    semctl(semid,0,IPC_STAT,&semidbuf);
    printf(" sem nums : %ld\n" , semidbuf.sem_nsems);

    //分配内存
    unsigned short * array = calloc(semidbuf.sem_nsems,sizeof(unsigned long));

    //获取所有的信号量值
    semctl(semid,0,GETALL,array);

    for(int i = 0 ; i < semidbuf.sem_nsems; ++i)
        printf("semval[%d]=%d\n" , i, array[i]);

    free(array);

    return 0;
}

semop.c

#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/types.h>
#include <stdlib.h>
#include <time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <string.h>

int main(int argc ,char** argv ,char ** env)
{
    if(argc < 2){
        puts("pathname -n[IPC_NOWAIT] -u[SEM_UNDO] operation");
        return 0;
    }
    char ** p = argv;
    int flag = 0;

    //提取是否需要 IPC_NOWAIT , SEM_UNDO 的参数
    while(*p){
        if(strcmp(*p,"n") == 0 || strcmp(*p,"-n") == 0) {
            flag |= IPC_NOWAIT;
        }
        if(strcmp(*p,"u") == 0 || strcmp(*p,"-u") == 0) {
            flag |= SEM_UNDO;
        }
        *p++;
    }

    //sem_op 的数量
    int count = argc - 2;

    // sem_op 的起始位置
    int oper_index = 2;

    if(flag & IPC_NOWAIT) {--count; ++oper_index;}
    if(flag & SEM_UNDO) {--count;++oper_index;}

    //获取信号量集
    int semid = semget(ftok(argv[1],0),0,0);
    printf("semid:%d\n" , semid);

    struct semid_ds semstat = {0};

    //获取信号量数量
    semctl(semid,0,IPC_STAT,&semstat);
    
    //获取最多可操作数
    int nsems = semstat.sem_nsems > count ? count :semstat.sem_nsems ;

    printf("input n:%d, sem num : %d ,nsems:%d, operindex:%d\n",
    count,semstat.sem_nsems,nsems,oper_index);

    struct sembuf *ptr = 0;

    //分配内存
    ptr = calloc(nsems, sizeof(struct sembuf));

    //赋值操作
    for(int i = 0 ; i < nsems; ++i){
        ptr[i].sem_num = i;
        ptr[i].sem_op = atoi(argv[oper_index+i]);
        ptr[i].sem_flg = flag;
        printf("ptr[%d]=%d\n" , i,ptr[i].sem_op);
    }

    if(semop(semid,ptr,nsems) < 0)
        perror("semop failed");
    else
        puts("success");



    return 0;
}

猜你喜欢

转载自blog.csdn.net/dashoumeixi/article/details/84627088
今日推荐