• IO进线程:信号灯


    二值信号灯:值为0或1。与互斥锁类似,资源可用时值为1,不可用时值为0。

    计数信号灯:值在0到n之间。用来统计资源,其值代表可用资源数

    等待操作是等待信号灯的值变为大于0,然后将其减1;而释放操作则相反,用来唤醒等待资源的进程或者线程

    System V的信号灯是一个或者多个信号灯的一个集合。其中的每一个都是单独的计数信号灯。而Posix信号灯指的是单个计数信号灯

    System V 信号灯由内核维护

    主要函数semget,semop,semctl

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

    #define WRITE 0    # 生产者编号
    #define READ 1     # 消费者编号

    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) */
    };


    int main(int argc, char *argv[])

        //1、创建共享内存
        key_t key = ftok(".", 'a');
        if (key < 0)
        {
            perror("ftok");
            return -1;
        }
    //  int shmid = shmget(IPC_PRIVATE, 1024, IPC_CREAT|0777);
        int shmid = shmget(key, 1024, IPC_CREAT|0777);
        if (shmid < 0)
        {
            perror("shmget");
            return -1;
        }
        //2. 把共享内存映射到用户空间
        char *addr = shmat(shmid, NULL, 0);
        if ((void *)-1 == addr)
        {
            perror("shmat");
            return -1;
        }
        //初始化信号灯集:可生产不可消费 编号:0:生产者  1:消费者
        int semid = semget(IPC_PRIVATE, 2, IPC_CREAT|0777);
        if (semget < 0)
        {
            perror("semget");
            return -1;
        }
        union semun sem0 = {1};
        semctl(semid, WRITE, SETVAL, sem0);  //生产者初始值:1
        union semun sem1 = {0};
        semctl(semid, READ, SETVAL, sem1);  //消费者初始值:0
        
        pid_t pid;
        if (0 > (pid = fork()))
        {
            perror("fork");
            return -1;
        }
        else if (0 == pid)  //生产者
        {
            while (1)
            {
                //申请生产者的资源
                struct sembuf sem0 = {WRITE, -1, 0};  //生产者:P操作
                semop(semid, &sem0, 1);

                printf("Input: ");
                fgets(addr, 1024, stdin);
                //释放消费者资源
                struct sembuf sem1 = {READ, 1, 0}; //消费者:V操作
                semop(semid, &sem1, 1);
                
                if (strncmp(addr, "quit", 4) == 0)
                    break;
            }
            exit(0);
        }
        //消费者
        while (1)
        {
            //申请消费者资源
            struct sembuf sem1 = {READ, -1, 0};  //消费者:P操作
            semop(semid, &sem1, 1);
            
            printf("Recv: %s\n", addr);
            //释放生产者资源
            struct sembuf sem0 = {WRITE, 1, 0};  //生产者:V操作
            semop(semid, &sem0, 1);

            if (strncmp(addr, "quit", 4) == 0)
                break;
        }
        //3. 解除映射
        sleep(1);
        if (0 > shmdt(addr))
        {
            perror("shmdt");
            return -1;
        }
        //4. 销毁共享内存
        if (0 > shmctl(shmid, IPC_RMID, NULL))
        {
            perror("shmctl");
            return -1;
        }

        if (0 > semctl(semid, IPC_RMID, 0))
        {
            perror("semctl");
            return -1;
        }

        return 0;

     

  • 相关阅读:
    70.Qt QWaitCondition多线程同步介绍及案例分析
    数据结构——线性表之顺序表
    【场景化解决方案】连接“云上管车”与道闸系统,企业用车流程更高效
    Android 创建桌面组件Widget——构建应用微件(二)
    死锁的Demo,产生条件
    [wp]NewStarCTF 2023 WEEK5|WEB
    创建型模式 - 简单工厂模式StaticFactoryMethod
    Linux与Shell学习--shell系列5--Shell运算符1(算数运算符和关系运算符)
    在idea中创建spring 微服务(boot)的Gradle项目 讲的很详细的
    利用多线程和queue实现生产-消费者模式--消息队列
  • 原文地址:https://blog.csdn.net/qq_63626307/article/details/126515715