信号量

  • sys/sem.h
#include <sys/sem.h>


int main(void) {
    // 创建新的或者获取已有的信号量集
    /*
     * semget 创建新的或者获取已有的信号量集
     *  key: ftok函数返回的key
     *  nsems int 信号量集中信号量个数
     *  semflg 标志位置
     * */
    // 操作信号量

    /*
     * semop  操作信号量
     *  semid int semget返回的信号量ID
     *  sops struct sembuf* 操作结构数组
     *          struct sembuf {
                    unsigned short  sem_num; // 信号量在信号量集中的编号(编号从0开始)
                    short           sem_op;  // 操作数 3表示,释放资源3个,-2表示拿走资源2个
                    short           sem_flg; // 操作标志 如果标志位包含 IPC_NOWAIT,在资源不够时不等待直接返回-1,errno设置为EAGAIN
                };
     *  nsops unsigned int 操作结构数
     * */


    // 销毁信号量集
    /*
     * semctl
     * semid int msgget获取的消息队列ID
     * num  int 需要操作的信号量编号(从0开始)
     * cmd   要做的操作
     *      IPC_RMID 销毁共享内存
     *      GETALL 获取所有信号量的值 buf传入数组,通过buf获取所有值 例如: unsigned short values[4]
     *      SETALL 设置所有信号量的值 buf传入数组,通过buf设置所有值 例如: unsigned short values[4]={1,2,3,4}
     *      GETVAL 获取特定信号量的值
     *      SETVAL 设置特定信号量的值 buf传入int
     *
     *  buf NULL
     *  成功返回0 失败返回-1
     *  注:在销毁时,如果有进程阻塞在semop函数,会立即返回-1,并且errno设置为ERMID
     * */
    return 0;
}
  • 练习
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
#include <sys/sem.h>
#define ARR_SIZE(arr) sizeof((arr))/sizeof((arr)[0])
const unsigned short BOOK_MAX_COUNT = 8;

typedef int(*Handler)(int, int, short);

typedef struct {
    char name[128];
    short count;
    int index;
    Handler handler;
} hbuf;

int handler(int semId, int index, short count) {
    // 1. 表示未借书  2. 表示书已借完 0.表示正常 -1 表示其他错误
    // 取出当前数值做判断
    int value;
    value = semctl(semId, index, GETVAL, NULL);
    if (value == BOOK_MAX_COUNT && count > 0) {
        return 1;
    }
    if (value == 0 && count < 0) {
        return 2;
    }
    struct sembuf buf = {index, count, 0};
    return semop(semId, &buf, 1);
}

// 判断字符串是否为数字
int isNumber(char *s) {
    if (strspn(s, "1234567890") == strlen(s)) {
        return 1;
    } else {
        return 0;
    }
}

int main() {
    // 初始化图书
    char *books[5] = {"书本1", "书本2", "书本3", "书本4", "书本5"};
    // 生成KEY
    key_t key = ftok(".", 8);
    printf("%d,生成key.\n", getpid());
    // 创建信号量
    printf("%d,创建信号量.\n", getpid());
    int semID = semget(key, ARR_SIZE(books), IPC_CREAT | 0664);
    if (semID == -1) {
        perror("semget");
        return -1;
    }
    char *js = "借";
    char *hs = "还";

    // 初始化操作
    hbuf *handlers[ARR_SIZE(books) * 2] = {};
    for (int i = 0; i < (ARR_SIZE(books)); i++) {
        // 每本书有两个借还两个操作
        // 0     1    2
        // 0,1   2,3  4,5

        hbuf *j = (hbuf *) malloc(sizeof(hbuf));
        hbuf *h = (hbuf *) malloc(sizeof(hbuf));
        strcat(j->name, js);
        strcat(h->name, hs);
        strcat(j->name, books[i]);
        strcat(h->name, books[i]);
        j->count = -1;
        j->index = i;
        j->handler = handler;
        h->count = 1;
        h->index = i;
        h->handler = handler;
        handlers[i * 2] = h;
        handlers[i * 2 + 1] = j;
    }

    // 初始化信号量
    unsigned short values[ARR_SIZE(books)] = {};
    for (int i = 0; i < ARR_SIZE(books); i++) {
        values[i] = BOOK_MAX_COUNT;
    }
    semctl(semID, 0, SETALL, values);
    // 打印选项
    char *cindex = malloc(sizeof(char) * 128);
    int index;
    for (;;) {
        printf("==================\n");
        // 获取所有信号集的数量
        semctl(semID, 0, GETALL, values);
        for (int i = 0; i < ARR_SIZE(handlers); i++) {
            printf("%d.%s 剩余:%d\n", i, handlers[i]->name, values[handlers[i]->index]);
        }
        printf(">> ");
        scanf("%s", cindex);
        if (strcmp(cindex, "!") == 0) {
            printf("结束\n");
            break;
        }
        if (isNumber(cindex) == 0) {
            printf("输入不合法\n");
            continue;
        }
        index = atoi(cindex);
        if (index >= ARR_SIZE(handlers)) {
            printf("超长输入不合法\n");
            continue;
        }
        int handler_val = handlers[index]->handler(semID, handlers[index]->index, handlers[index]->count);
        if (handler_val == -1) {
            perror("handlers");
            return -1;
        } else if (handler_val == 1) {
            printf("未借书,不需要还书\n");
        } else if (handler_val == 2) {
            printf("书已借完,不能借书\n");
        }

    }
    // 释放内存
    printf("释放内存\n");
    for (int i = 0; i < ARR_SIZE(handlers); i++) {
        free(handlers[i]);
    }
    free(cindex);
    // 释放信号量集
    printf("释放信号量集\n");
    semctl(semID, 0, IPC_RMID, NULL);
}

posted on 2023-05-04 11:16  信奉上帝的小和尚  阅读(20)  评论(0编辑  收藏  举报

导航