IPC (cinco) --------- semáforo

1. Introducción a los semáforos y conjuntos de semáforos

      1. Se utiliza para la exclusión mutua y la sincronización entre procesos para controlar el acceso a los recursos compartidos.

      2. Para facilitar el funcionamiento de una gran cantidad de recursos compartidos, se introduce un conjunto de semáforos y cada recurso compartido corresponde a un semáforo.

      3. Operaciones de semáforo: operación P (restar el semáforo) y operación V (agregar al semáforo).

 

Dos API relacionadas con el semáforo

      1. Crea un conjunto de semáforos

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

          parámetro:

          clave: el valor clave del conjunto de semáforos especificado por el usuario

          nsems: el número de semáforos en el conjunto de semáforos

          bandera: una combinación de IPC_CREAT, IPC_EXCL y otros permisos.

         Retorno: Devuelve el ID del conjunto de semáforos en caso de éxito, devuelve -1 en caso de error

      2. Control de conjunto de semáforos

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

           union semnu {

                 int val;

                struct semid_ds * buf;

                corto sin firmar * arry;

         };

         parámetro:

          semid: ID de conjunto de semáforos

          semnu: 0 significa operar en todos los semáforos, el número de semáforo comienza desde 0

          val: Obtiene o el valor de un semáforo en el conjunto de semáforos

          buf: puntero de atributo de conjunto de semáforo

          arry: Obtiene o establece el valor de todos los semáforos en el conjunto de semáforos.

          cmd:

          3. Operación de conjunto de semáforos (operaciones de suma y resta en el semáforo en el conjunto de semáforos (operación PV))

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

          struct sembuf {

                sem_num corto sin firmar;

               sem_op corto;

               sem_flag corto; 

        };

       

         parámetro:

          semid: ID de conjunto de semáforos

          sops: puntero de matriz de estructura sembuf

          nsops: el número de semáforos en sops, sizeof (sops) / sizeof (sops [0])

         sem_num: el número del semáforo en el conjunto de semáforos

         sep_op: el número positivo es la operación V (sumar la operación al semáforo), el número negativo es la operación P (restar el semáforo)

         sem_flag: generalmente SEM_UNDO

        regreso:

          Devuelve 0 en caso de éxito; devuelve -1 en caso de error.

 

  Tres, prueba de código

          Tarea: Cree una memoria compartida y dos procesos P1 y P2. P1 escribe datos en la memoria compartida. Después de escribir, P2 lee datos de la memoria compartida. Después de leer P2, P1 continúa escribiendo y luego se repite.

        

       el código se muestra a continuación:

       

#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;
}

Resultados de la prueba:

  

Supongo que te gusta

Origin blog.csdn.net/weixin_40204595/article/details/112940807
Recomendado
Clasificación