Linux进程间通信第四讲 标准IPC之信号量集

目录

4.3信号量集

4.3.1 概念和原理

4.3.2 使用


4.3信号量集

4.3.1 概念和原理

(不是用于进程间传递数据、而是用于进程间访问控制)

信号量集是一个信号量的集合,可以存放多个信号量

而信号量就是一个计数器, 用于记录进程的访问次数, 每来一个进程访问计数值-1(P操作),每离开一个进程计数值+1(V操作)

当计数值为0时就不在允许进程访问,直到计数值重新大于0为止才能允许

那什么时候用到这个呢?

之前在共享内存后面我提到一个问题

扫描二维码关注公众号,回复: 9591068 查看本文章

如果对于同一个资源, 一个进程对它写, 同时另一个进程又对它读

这会乱 !!!

因此才需要进程的互斥和同步解决上述遇到的问题

进程的互斥和同步就是用到了信号量集

下面来看下它如何使用吧

4.3.2 使用

    1)ftok获取key

    2)通过key创建/获取信号量集 ------- semget 

          

         参数:

                key - 上一步获取的key

                nsems - 信号量集中信号量的个数(信号量集的长度)

                semflg - 创建标志和权限

                IPC_CREAT|0666

    3)如果是创建需要设置信号量集中信号量的初始计数 ----- semctl

            semctl(信号量集ID,信号量在信号量集中的下标,SETVAL,初始计数值);    

    4)对信号量进行P-V操作 ------ semop

          

          参数:

                    semid - 信号量集的ID

                    sops - 信号量操作数组首地址

                    nsops - 信号量操作数组的元素个数

                    成功返回0,失败返回-1

struct sembuf结构体中包含以下成员:
    unsigned short sem_num;  /* 信号量的下标 */
    short          sem_op;   /* 操作方式 -1 / 1 */
    short          sem_flg;  /* 等待方式: 0:阻塞方式 IPC_NOWAIT:非阻塞方式*/

    5)不再使用可以删除 -------- semctl

进程1创建共享内存, 因为要和进程2访问同一个资源所以再创建一个信号量集,进程1的代码如下:(进程的互斥)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <signal.h>

void *p = NULL;
int shmid,semid;

void func(int sig)
{
    shmdt(p);
    shmctl(shmid,IPC_RMID,0);
    exit(0);
}

int main()
{
    char buf[100] = {};
    signal(SIGINT,func);

    //1.获取key
    key_t key = ftok(".",'x');
    if(key==-1){
        perror("ftok");
        exit(-1);
    }

    //2.创建共享内存
    shmid = shmget(key,100,IPC_CREAT|0666);
    if(shmid==-1){
        perror("shmget");
        exit(-1);
    }

    //3.映射共享内存
    p = shmat(shmid,0,0);
    if(p==(void *)-1){
        perror("shmat");
        exit(-1);
    }

    //4.创建信号量集
    semid = semget(key,1,IPC_CREAT|0666);
    if(semid==-1){
        perror("semget");
        exit(-1);
    }

    //5.设置信号量初始值1
    int res = semctl(semid,0,SETVAL,1);
    if(res==-1){
        perror("semctl");
        exit(-1);
    }

    while(1){
        //P操作, 信号量-1
        struct sembuf sem;
        sem.sem_num = 0;
        sem.sem_op = -1;
        sem.sem_flg = 0;
        semop(semid,&sem,1);

        //写共享内存,发送
        printf("请输入:");
        fgets(buf,sizeof(buf),stdin);
        buf[strlen(buf)-1] = 0;
        
        strcpy((char *)p,buf);

        //V操作,信号量+1
        sem.sem_op = 1;
        semop(semid,&sem,1);
    }

    return 0;
}

进程2的代码如下:(进程的互斥)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <signal.h>

void *p = NULL;
int shmid,semid;

void func(int sig)
{
    shmdt(p);
    semctl(semid,0,IPC_RMID);
    exit(0);
}

int main()
{
    signal(SIGINT,func);

    //1.获取key
    key_t key = ftok(".",'x');
    if(key==-1){
        perror("ftok");
        exit(-1);
    }

    //2.共享内存
    shmid = shmget(key,0,0);
    if(shmid==-1){
        perror("shmget");
        exit(-1);
    }

    //3.映射共享内存
    p = shmat(shmid,0,0);
    if(p==(void *)-1){
        perror("shmat");
        exit(-1);
    }

    //4.信号量集
    semid = semget(key,0,0);
    if(semid==-1){
        perror("semget");
        exit(-1);
    }

    while(1){
        //P操作, 信号量-1
        struct sembuf sem;
        sem.sem_num = 0;
        sem.sem_op = -1;
        sem.sem_flg = 0;
        semop(semid,&sem,1);

        printf("%s\n",(char *)p);

        //V操作,信号量+1
        sem.sem_op = 1;
        semop(semid,&sem,1);
    }

    return 0;
}
发布了52 篇原创文章 · 获赞 40 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/weixin_40519315/article/details/104211027