• 封装一个信号量集操作函数的工具


    信号量的概念参见这里

    与消息队列和共享内存一样,信号量集也有自己的数据结构:

    struct semid_ds {
    struct ipc_perm sem_perm;  /* Ownership and permissions */
    time_t     sem_otime; /* Last semop time */
    time_t     sem_ctime; /* Last change time */
    unsigned short  sem_nsems; /* No. of semaphores in set */
    };


    同样地,第一个条目也是共有的ipc 对象内核结构,剩下的是私有成员。


     Each semaphore in a semaphore set has the following associated values:

               unsigned short  semval;   /* semaphore value */
               unsigned short  semzcnt;  /* # waiting for zero */
               unsigned short  semncnt;  /* # waiting for increase */
               pid_t           sempid;   /* process that did last op */

    即每一个在信号量集中的信号量都有上述4个相关的变量。

    1、semval :当前某信号量的资源数目

    2、semzcnt:当sem_op(见 struct sembuf)为0,且semop 函数没有设置IPC_NOWAIT 标志,且当前semval 不为0,此时semzcnt 会加1,表示等待这个信号量的资源变为0的进程数加1,且进程会阻塞等待直到4个事件其中一个发生,具体可man 2 semop 一下。

    3、semncnt:当sem_op(见 struct sembuf)< 0,且semop 函数没有设置IPC_NOWAIT 标志,且当前semval < |sem_op| ,此时semncnt 会加1,表示等待这个信号量的资源增加的进程数加1,且进程会阻塞等待直到4个事件其中一个发生,具体可man 2 semop 一下。

    4、当正确执行了semop 函数,则信号量集中的每个信号量的sempid 参数都被设置为改变此信号量的进程pid。


    以下是几个信号量集操作函数:

    #include <sys/types.h>
    #include <sys/ipc.h>
    #include <sys/sem.h>

    int semget(key_t key, int nsems, int semflg);
    int semctl(int semid, int semnum, int cmd, ...);
    int semop(int semid, struct sembuf *sops, unsigned nsops);


    功能:用来创建和访问一个信号量集
    原型 int semget(key_t key, int nsems, int semflg);
    参数
    key: 信号量集的名字
    nsems:信号量集中信号量的个数
    semflg: 由九个权限标志构成,它们的用法和创建文件时使用的mode模式标志是一样的
    返回值:成功返回一个非负整数,即该信号量集的标识码;失败返回-1


    功能:用于控制信号量集
    原型 int semctl(int semid, int semnum, int cmd, ...);
    参数
    semid:由semget返回的信号量集标识码
    semnum:信号量集中信号量的序号,从0开始编号
    cmd:将要采取的动作(有三个可取值)
    最后一个参数是 union semun,具体成员根据cmd 的不同而不同

    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) */
               };
    返回值:成功返回0;失败返回-1

    cmd 取值如下:

    SETVAL  设置信号量集中的信号量的计数值
    GETVAL  获取信号量集中的信号量的计数值
    IPC_STAT 把semid_ds结构中的数据设置为信号量集的当前关联值
    IPC_SET 在进程有足够权限的前提下,把信号量集的当前关联值设置为semid_ds数据结构中给出的值
    IPC_RMID 删除信号量集


    功能:用来创建和访问一个信号量集
    原型 int semop(int semid, struct sembuf *sops, unsigned nsops);
    参数
    semid:是该信号量集的标识码,也就是semget函数的返回值
    sops:是个指向一个结构体的指针
    nsops:信号量的个数
    返回值:成功返回0;失败返回-1

    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操作,发出信号量已经变得可用。当然+-n 和0 都是允许的。需要注意的是只有+n 才确保将semval +n 后马上返回,而-n 和 0 很可能是会阻塞的,见文章上面的分析,+-n 需要进程对信号量集有写的权限,而0 只需要读的权限。


    sem_flag:的两个取值是IPC_NOWAIT或SEM_UNDO,设为前者如果当某个信号量的资源为0时进行P操作,此时不会阻塞等待,而是直接返回资源不可用的错误;设为后者,当退出进程时对信号量资源的操作撤销;不关心时设置为0即可。

    当要对一个信号量集中的多个信号量进行操作时,sops 是结构体数组的指针,此时nsops 不为1。此时对多个信号量的操作是作为一个单元原子操作,要么全部执行,要么全部不执行。


    下面来封装一个信号量集操作函数的工具:

    semtool.c

     C++ Code 
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
     
    #include <sys/types.h>
    #include <unistd.h>
    #include <sys/ipc.h>
    #include <sys/sem.h>
    #include <errno.h>
    #include <stdio.h>
    #include <stdlib.h>

    #define ERR_EXIT(m) 
            do 
            { 
                    perror(m); 
                    exit(EXIT_FAILURE); 
            } while(0)

    union semun
    {
        int val;                  /* value for SETVAL */
        struct semid_ds *buf;     /* buffer for IPC_STAT, IPC_SET */
        unsigned short *array;    /* array for GETALL, SETALL */
        /* Linux specific part: */
        struct seminfo *__buf;    /* buffer for IPC_INFO */
    };

    int sem_create(key_t key)
    {
        int semid = semget(key, 1, 0666 | IPC_CREAT | IPC_EXCL);
        if (semid == -1)
            ERR_EXIT("semget");

        return semid;
    }

    int sem_open(key_t key)
    {
        int semid = semget(key, 0, 0);
        if (semid == -1)
            ERR_EXIT("semget");

        return semid;
    }

    int sem_p(int semid)
    {
        struct sembuf sb = {0, -1, /*IPC_NOWAIT*/SEM_UNDO};
        int ret = semop(semid, &sb, 1);
        if (ret == -1)
            ERR_EXIT("semop");

        return ret;
    }

    int sem_v(int semid)
    {
        struct sembuf sb = {0, 1, /*0*/SEM_UNDO};
        int ret = semop(semid, &sb, 1);
        if (ret == -1)
            ERR_EXIT("semop");

        return ret;
    }

    int sem_d(int semid)
    {
        int ret = semctl(semid, 0, IPC_RMID, 0);
        if (ret == -1)
            ERR_EXIT("semctl");
        return ret;
    }

    int sem_setval(int semid, int val)
    {
        union semun su;
        su.val = val;
        int ret = semctl(semid, 0, SETVAL, su);
        if (ret == -1)
            ERR_EXIT("semctl");

        printf("value updated... ");
        return ret;
    }

    int sem_getval(int semid)
    {
        int ret = semctl(semid, 0, GETVAL, 0);
        if (ret == -1)
            ERR_EXIT("semctl");

        printf("current val is %d ", ret);
        return ret;
    }

    int sem_getmode(int semid)
    {
        union semun su;
        struct semid_ds sem;
        su.buf = &sem;
        int ret = semctl(semid, 0, IPC_STAT, su);
        if (ret == -1)
            ERR_EXIT("semctl");

        printf("current permissions is %o ", su.buf->sem_perm.mode);
        return ret;
    }

    int sem_setmode(int semid, char *mode)
    {
        union semun su;
        struct semid_ds sem;
        su.buf = &sem;

        int ret = semctl(semid, 0, IPC_STAT, su);
        if (ret == -1)
            ERR_EXIT("semctl");

        printf("current permissions is %o ", su.buf->sem_perm.mode);
        sscanf(mode, "%o", (unsigned int *)&su.buf->sem_perm.mode);
        ret = semctl(semid, 0, IPC_SET, su);
        if (ret == -1)
            ERR_EXIT("semctl");

        printf("permissions updated... ");

        return ret;
    }

    void usage(void)
    {
        fprintf(stderr, "usage: ");
        fprintf(stderr, "semtool -c ");
        fprintf(stderr, "semtool -d ");
        fprintf(stderr, "semtool -p ");
        fprintf(stderr, "semtool -v ");
        fprintf(stderr, "semtool -s <val> ");
        fprintf(stderr, "semtool -g ");
        fprintf(stderr, "semtool -f ");
        fprintf(stderr, "semtool -m <mode> ");
    }

    int main(int argc, char *argv[])
    {
        int opt;

        opt = getopt(argc, argv, "cdpvs:gfm:");
        if (opt == '?')
            exit(EXIT_FAILURE);
        if (opt == -1)
        {
            usage();
            exit(EXIT_FAILURE);
        }

        key_t key = ftok(".", 's');
        int semid;
        switch (opt)
        {
        case 'c':
            sem_create(key);
            break;
        case 'p':
            semid = sem_open(key);
            sem_p(semid);
            sem_getval(semid);
            break;
        case 'v':
            semid = sem_open(key);
            sem_v(semid);
            sem_getval(semid);
            break;
        case 'd':
            semid = sem_open(key);
            sem_d(semid);
            break;
        case 's':
            semid = sem_open(key);
            sem_setval(semid, atoi(optarg));
            break;
        case 'g':
            semid = sem_open(key);
            sem_getval(semid);
            break;
        case 'f':
            semid = sem_open(key);
            sem_getmode(semid);
            break;
        case 'm':
            semid = sem_open(key);
            sem_setmode(semid, argv[2]);
            break;
        }

        return 0;
    }

    首先来介绍一个getopt 函数, int getopt(int argc, char * const argv[],const char *optstring);

    可以解析命令行选项参数,前两个参数由main 函数传递,第三个参数是一个字符串集,即解析命令行参数看是否存在这些字符。如./semtool -s 3 则s

    为选项,3为选项参数,optarg 是一个全局指针变量  extern char *optarg;  通过atoi(optarg) 可以获取数字3。



    使用方法。


    // optind: the index of first argument which has no option


    // after getopt loop end: ./main -a xxx -b xxx ip port cnt    optind points to ip


    // usually optind+1 <= argc when no option arguments needed.

    // argc: the count of arguments include exe; agrv[0 ~ argc-1]




    key 已存在时返回错误,不再创建信号量集,而我们使用了ftok 函数产生一个唯一的key,传入的参数一定,则每次产生的key 值


    样,当第二次次执行./semtool -c ,会返回file exist 的错误,当然先删除当前信号量集,再create 是可以的,此时虽然key 还是一样


    的,但返回的semid 是不同的。




    simba@ubuntu:~/Documents/code/linux_programming/UNP/system_v$ ipcs -s


    ------ Semaphore Arrays --------
    key        semid      owner      perms      nsems     


    simba@ubuntu:~/Documents/code/linux_programming/UNP/system_v$ ./semtool 
    usage:

    semtool -c

    semtool -d

    semtool -p

    semtool -v

    semtool -s <val>

    semtool -g

    semtool -f

    semtool -m <mode>

    simba@ubuntu:~/Documents/code/linux_programming/UNP/system_v$ ./semtool -c

    simba@ubuntu:~/Documents/code/linux_programming/UNP/system_v$ ipcs -s


    ------ Semaphore Arrays --------
    key         semid      owner      perms      nsems     
    0x730135db  98304      simba      666           1         


    simba@ubuntu:~/Documents/code/linux_programming/UNP/system_v$ ./semtool -v

    current val is 1
    simba@ubuntu:~/Documents/code/linux_programming/UNP/system_v$ 

    simba@ubuntu:~/Documents/code/linux_programming/UNP/system_v$ ./semtool -v

    current val is 1

    simba@ubuntu:~/Documents/code/linux_programming/UNP/system_v$ ./semtool -s 3

    value updated...

    simba@ubuntu:~/Documents/code/linux_programming/UNP/system_v$ ./semtool -g

    current val is 3

    simba@ubuntu:~/Documents/code/linux_programming/UNP/system_v$ ./semtool -p

    current val is 2

    simba@ubuntu:~/Documents/code/linux_programming/UNP/system_v$ ./semtool -m 600

    current permissions is 666

    permissions updated...

    simba@ubuntu:~/Documents/code/linux_programming/UNP/system_v$ ./semtool -d

    simba@ubuntu:~/Documents/code/linux_programming/UNP/system_v$ ipcs -s


    ------ Semaphore Arrays --------
    key        semid      owner      perms      nsems     

    可以设置信号量的资源数。ipcs -s 输出中的nsems 表示信号量的个数,当前只有一个;./semtool -v 输出中的current value 表示这个信号量的资源数。


    参考:《UNP》

  • 相关阅读:
    OCP-1Z0-052-V8.02-167题
    OCP-1Z0-052-V8.02-172题
    OCP-1Z0-052-V8.02-178题
    OCP-1Z0-052-V8.02-180题
    OCP-1Z0-052-V8.02-84题
    OCP-1Z0-052-V8.02-86题
    OCP-1Z0-052-V8.02-85题
    OCP-1Z0-052-V8.02-83题
    OCP-1Z0-052-V8.02-76题
    OCP-1Z0-052-V8.02-75题
  • 原文地址:https://www.cnblogs.com/alantu2018/p/8473142.html
Copyright © 2020-2023  润新知