[置顶] Linux 下进程间通信机制(六) 信号灯集 Semaphore Arrays

信号灯集函数定义如下:


#include <sys/sem.h>
int semctl(int sem_id, int sem_num, int command, ...);
int semget(key_t key, int num_sems, int sem_flags);
int semop(int semid, struct sembuf *sops, unsigned nsops);




semget函数创建一个新的信号量或是获得一个已存在的信号量键值。
semop函数用来改变信号量的值(包含P操作和V操作)。
semctl函数允许信号量信息的直接控制(包含初始化信号灯和删除信号灯)。




事实上,为了获得我们特定操作所需要的#define定义,我们需要在包含sys/sem.h文件之前通常需要包含sys/types.h与sys/ipc.h文件。




相关的类型定义:


struct  sembuf{
  unsigned short sem_num;  /* semaphore number *//*信号灯在信号灯集中的编号*/
  short          sem_op;   /* semaphore operation *//*P操作或者V操作*/
  short          sem_flg;  /* operation flags */
};



//这个联合体需要在程序声明,用于semctl函数的SETVAL选项的传值,作为第四个参数。
union semun {
int val;
struct semid_ds *buf;
unsigned short *array;
}




demo

进程间利用共享内存机制通信,一个进程写,一个进程读,用信号灯同步。


//writer.c
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/shm.h>

#define R 0
#define W 1
#define N 1024

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

void pv(int semid, int op, int num)
{
    struct sembuf buf;
    buf.sem_num = num;//信号灯编号
    buf.sem_op = op;  //p操作或者v操作
    buf.sem_flg = 0;
 /*semid为信号灯集id, buf为struct sembuf结构体指针, 1表示操作信号灯的个数为1,如果大于一,表示操纵多个(则buf为struct sembuf结构体的数组指针)*/
    if (semop(semid, &buf, 1) == -1)
    {
        perror("semop");
        exit(-1);
    }    
}

int main()
{
    int semid, shmid;
    key_t key;
    char *shmaddr;
   
    if ((key = ftok(".", 'a')) == -1)
    {
        perror("ftok");
        exit(-1);
    }
    //先启动的进程负责进行初始化,信号灯集中由两个信号灯,一个为读,一个为写
    if ((semid = semget(key, 2, 0666 | IPC_CREAT | IPC_EXCL)) == -1)
    {
        if (errno == EEXIST)
        {
            semid = semget(key, 2, 0666);
        }
    }
    else    //first
    {
        union semun un;

        un.val = 0;
        //读的信号灯值为0
        if (semctl(semid, R, SETVAL, un) == -1)
        {
            perror("init R");
            exit(-1);
        }
	 //写的信号灯值为1
        un.val = 1;
        if (semctl(semid, W, SETVAL, un) == -1)
        {
            perror("init R");
            exit(-1);
        }
    }
    //创建共享内存
    if ((shmid = shmget(key, N, 0666 | IPC_CREAT)) == -1)
    {
        perror("shmget");
        exit(-1);
    }
    //映射共享内存
    if ((shmaddr = (char *)shmat(shmid, NULL, 0)) == (char *)-1)
    {
        perror("shmaddr");
        exit(-1);
    }

    while (1)
    {
        //p(w) fgets v(r)
        
	 pv(semid, -1, W);
        fgets(shmaddr, N, stdin);
        pv(semid, 1, R);
        if (strncmp(shmaddr, "quit", 4) == 0)
            break;
    }

    usleep(100000);

    if(semctl(semid, 0, IPC_RMID) == -1)
    {
        perror("rm sem");
        exit(-1);
    }

    if (shmdt(shmaddr) == -1)
    {
        perror("shmdt");
        exit(-1);
    }

    if (shmctl(shmid, IPC_RMID, NULL) == -1)
    {
        perror("shmctl");
        exit(-1);
    }

    exit(0);
}


//reader.c
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/shm.h>

#define R 0
#define W 1
#define N 1024

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

void pv(int semid, int op, int num)
{
    struct sembuf buf;
    buf.sem_num = num;
    buf.sem_op = op;
    buf.sem_flg = 0;

    if (semop(semid, &buf, 1) == -1)
    {
        perror("semop");
        exit(-1);
    }    
}

int main()
{
    int semid, shmid;
    key_t key;
    char *shmaddr;

    if ((key = ftok(".", 'a')) == -1)
    {
        perror("ftok");
        exit(-1);
    }

    if ((semid = semget(key, 2, 0666 | IPC_CREAT | IPC_EXCL)) == -1)
    {
        if (errno == EEXIST)
        {
            semid = semget(key, 2, 0666);
        }
    }
    else    //first
    {
        union semun un;

        un.val = 0;
        if (semctl(semid, R, SETVAL, un) == -1)
        {
            perror("init R");
            exit(-1);
        }

        un.val = 1;
        if (semctl(semid, W, SETVAL, un) == -1)
        {
            perror("init R");
            exit(-1);
        }
    }

    if ((shmid = shmget(key, N, 0666 | IPC_CREAT)) == -1)
    {
        perror("shmget");
        exit(-1);
    }

    if ((shmaddr = (char *)shmat(shmid, NULL, 0)) == (char *)-1)
    {
        perror("shmaddr");
        exit(-1);
    }

    srandom(getpid());
    while (1)
    {
        //p(r) printf v(w)
        pv(semid, -1, R);
        printf("%s", shmaddr);
        if (strncmp(shmaddr, "quit", 4) == 0)
        {
            //v(r)
            pv(semid, 1, R);
            break;
        }
        pv(semid, 1, W);
        sleep(random()%5+1);
    }

    if (shmdt(shmaddr) == -1)
    {
        perror("shmdt");
        exit(-1);
    }

    exit(0);
}


你可能感兴趣的:(linux,struct,Semaphore,null,Arrays,buffer)