IPC(五)---------信号量

一、信号量和信号量集简介

      1、用于进程间的互斥和同步,来控制对共享资源的访问。

      2、为了便于对大量共享资源的操作引入了信号量集,每个共享资源对应一个信号量。

      3、信号量的操作:P(对信号量减)操作和V(对信号量加)操作。

二、信号量相关API

      1、创建信号量集

          int semget(key_t key,int nsems,int flag);

          参数:

          key:用户指定的信号量集键值

          nsems: 信号量集合中的信号量个数

          flag:IPC_CREAT、IPC_EXCL等权限的组合。

         返回: 成功返回信号量集ID,失败返回-1

      2、信号量集控制

           int semctl(int semid, int semnum, int cmd, .../* union semnu arg*/);

           union semnu {

                 int val;

                struct semid_ds *buf;

                unsigned short *arry;

         };

         参数:

          semid: 信号量集ID

          semnu: 0表示对所有信号量操作,信号量编号从0开始

          val: 获取或者信号量集中某个信号量的值

          buf: 信号量集属性指针

          arry:获取或设置信号量集中所有信号量的值。

          cmd:

          3、信号量集操作(对信号量集中的信号量做加和减操作(PV操作))

           int semop(int semid, struct sembuf * sops, size_t nsops);

          struct sembuf{

                unsigned short sem_num;

               short sem_op;

               short sem_flag; 

        };

       

         参数:

          semid:  信号量集ID

          sops:sembuf 结构体数组指针

          nsops:sops中信号量的个数,sizeof(sops)/sizeof(sops[0])

         sem_num: 信号量集中信号量的编号

         sep_op:  正数为V 操作(对信号量加操作),负数为P操作(对信号量减)

         sem_flag:一般为SEM_UNDO

        返回:

          成功返回0;出错返回-1。

  三、代码测试

          任务:创建一块共享内存和两个进程P1和P2,P1向共享内存中写数据,写完后,P2从共享内存中读取数据,P2读完后P1继续写,然后依次循环。

        

       代码如下:

       

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


typedef union {
    
    int val;
    struct semid_ds *buf;
    unsigned short* arry;
}semnn_u;

typedef struct
{
    int val;    
    int semid;

}Storage_t;//共享内存的数据结构


int create_sem(Storage_t * s)
{

    //创建两个信号量
    s->semid = semget(IPC_PRIVATE,2,IPC_CREAT|IPC_EXCL|0777);

    if(s->semid < 0)
    {
        printf("semget error\n");

        return -1;
    }

    //对信号量进行初始化,都初始化为0
    

    semnn_u nu;

    unsigned short val[2] = {0,0};
    nu.arry = val;


    if(semctl(s->semid,2,SETALL,nu) < 0)
    {
        printf("semctl error\n");

        return -1;
    }

    return 0;

    
}


void destory_sem(Storage_t *s)
{

    //销毁2个信号量
    if(semctl(s->semid,2,IPC_RMID,NULL) < 0)
    {
        printf("destory error\n");
    }

}

void writer(Storage_t *s ,int val)
{
    //将数据写入共享内存
    s->val = val;

    printf("writer:%d,pid:%d\n",val,getpid());
    //对S1做V操作
    //s1的sem_num是0
    struct sembuf sem_op_v = {0,1,SEM_UNDO};

    if(semop(s->semid,&sem_op_v,1) < 0)
    {
        printf("sem op error 1\n");
    }

    //对S2做P操作
    //s2的sem_nu是1
    struct sembuf sem_op_p = {1,-1,SEM_UNDO};

    if(semop(s->semid,&sem_op_p,1) < 0)
    {
        printf("sem op error 2\n");
    }
  
}


void reader(Storage_t * s)
{
    //先对S1做P操作
    struct sembuf  sem_op_p = {0,-1,SEM_UNDO};

    if(semop(s->semid,&sem_op_p,1) < 0)
    {
        printf("reader semop error 1\n");
    }

    //对共享内存数据进行读操作
    printf("reader: %d,pid:%d\n",s->val,getpid());

    //对S2做V操作
    struct sembuf sem_op_v = {1,1,SEM_UNDO};

    if(semop(s->semid,&sem_op_v,1) < 0)
    {
        printf("reader semop error 2\n");
    }
}

int main(void)
{
    //创建共享内存
    
    pid_t pid ;
    int shmid = shmget(IPC_PRIVATE,sizeof(Storage_t),IPC_CREAT|IPC_EXCL|0777);
        
	Storage_t *p;

	
	//将共享内存映射到本进程中
	p = (Storage_t *)shmat(shmid,0,0);

	if(p == (Storage_t *) -1)
	{
		printf("shmat error\n");
		return -1;
	}
    if(shmid < 0)
    {
        printf("shmget error\n");

        return -1;
    }

    //创建信号量
    create_sem(p);
    
    pid = fork();

    if(pid > 0)
    {
		//parent process
		printf("parent pid :%d\n",getpid());
        //向共享内存中写20次
        for(int i = 0; i < 20;i ++)
        {
            writer(p,i);
        }

        wait(0);//等待回收子进程
        
        destory_sem(p); //销毁信号量

        shmdt(p); //解除共享内存映射

        shmctl(shmid,IPC_RMID,NULL);//销毁共享内存
    }
    else if(pid == 0)
    {
        printf("child pid:%d\n",getpid());
        

        //从共享内存中读20次
        for(int i = 0;i < 20;i ++)
        {
            reader(p);
        }

        shmdt(p);
        
    }

    return 0;
}

测试结果:

  

猜你喜欢

转载自blog.csdn.net/weixin_40204595/article/details/112940807