进程间通信之信号量

时间:2022-12-20 15:12:31

信号量:相当于一个计数器,描述当前环境下临界资源的数目。信号量是用来保护临界资源的,而信号量本身也是临界资源。

生命周期:随内核。

原子性:即要么做,要么不做。

临界资源:不同进程可以看到的同一资源。

临界区:不同进程访问同一资源的代码区(write(),read())。

互斥:任一时刻,只有一个进程进入临界区访问临界资源,且访问时具有原子性。

同步:所有进程以某种顺序依次访问临界资源。

信号量的两个基本操作:P、V操作-----解决互斥和同步的问题。

P操作:申请资源,如果S>0,则S=S-1;如果S = 0,就挂起该进程的执行。

V操作:使用资源完毕,归还给系统,若有进程挂起,则唤醒等待进程,否则S=S+1。

代码如下:

comm.h:#ifndef _COMM_H#define _COMM_H#include<stdio.h>#include<sys/types.h>#include<sys/ipc.h>#include<sys/sem.h>#define PATHNAME "."#define PROJ_ID 0666union semun{    int val;    struct semid_ds *buf;     unsigned short *array;     struct seminfo *__buf;};//struct sembuf{//unsigned short sem_num; // semaphore number //short sem_op; // semaphore operation // short sem_flg; //operation flags //};int create_sem(int nsem);int get_sem();int destroy_sem(int semid);int init_sem(int semid,int which,int val);int P(int semid,int which);int V(int semid,int which);#endifcomm.c:#include"comm.h"static int comm_sem(int nsem ,int flag){    key_t key=ftok(PATHNAME,PROJ_ID);    int semid=semget(key,nsem,flag);    if(semid<0){        perror("semget");    }    return semid;}static op_sem(int semid,int op,int which){    struct sembuf _sembuf;    _sembuf.sem_op = op;    _sembuf.sem_num = which;    _sembuf.sem_flg = 0;    return semop(semid,&_sembuf,1);}int create_sem(int nsem){    return comm_sem(nsem,IPC_CREAT|IPC_EXCL|0666);}int get_sem(){    return comm_sem(0,IPC_CREAT);}int destroy_sem(int semid){    if(semctl(semid,0,IPC_RMID)<0)    {        perror("semctl");        return -1;    }    //printf("destroy sucess");    return 0;}int init_sem(int semid,int which,int _val){    union semun _semun;    _semun.val = _val;    if(semctl(semid,which,SETVAL,_semun)<0)    {        perror("semctl");        return -2;    }    return 0;}int P(int semid,int which){    return op_sem(semid,-1,which);}int V(int semid,int which){    return op_sem(semid,1,which);}sem.c:#include"comm.h"#include<stdlib.h>int main(){    int semid=create_sem(10);    init_sem(semid,0,1);    pid_t id=fork();    if(id<0)    {        perror("fork");        return -1;    }    else if(id ==0){//child        int sem_id=get_sem();        while(1)        {            P(sem_id,0);            printf("A");            fflush(stdout);            usleep(12345);            printf("A");            fflush(stdout);            usleep(13456);            V(sem_id,0);        }        exit(0);    }    else{//father        while(1)        {            P(semid,0);            printf("B");            fflush(stdout);            usleep(14345);            printf("B");            fflush(stdout);            usleep(13345);            V(semid,0);        }        wait(NULL);    }    destroy_sem(semid);    return 0;}Makefile:sem:comm.c sem.c    gcc -o $@ $^.PHONY:cleamclean:    rm -f sem