进程间通信之信号灯(信号量)

        在多个进程同时执行在执行通信时,由写部分必须有先后,为了保证按照指定的要求进行执行,这个时候就引入了生产者消费者模型。

何以为生产者、消费者?

生产者:就是制作一个可以通信的标志位,对标志位进行++操作,从而生产资源,也可理解为(释放资源,进V操作)。

if(完成某种操作)
{
    对信号量++;进行生产
}

消费者:顾名思义就是当生产者生产过后,其标志位发生变化,然后操作之后进行消费(申请资源,P操作 )。

while(1)
{
    if(已经生产)
    {
        标志位--;
        break;
    }
}

其实信号灯的操作就是这样,消费者随时去查看生产者生产没有,生产力消费者就消费。

下面则是使用信号灯所需要使用到的函数:

 1、创建、打开信号灯集        int semget()

//计算key值 
key_t ftok(const char *pathname, int proj_id); 

参数1:const char *pathname:文件路径 
参数2:int proj_id:
#include <sys/types.h> 
#include <sys/ipc.h> 
#include <sys/sem.h>

int semget(key_t key, int nsems, int semflg)

参数1:指定信号灯的key值
参数2:信号灯集中含有多少个信号量
参数3:访问权限     通常是    0666 | IPC_CREAT

返回值:
    成功:信号灯的id
    失败:-1

2、信号灯的操作(V操作、P操作,也可以叫做+、-操作)        int semop()

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

参数1:要操作的信号灯id
参数2:struct sembuf *sops结构体(要操作信号灯的结构体地址)
       struct sembuf        //信号量的值大于0
        {
            unsigned short sem_num;    要操作信号量编号
            short sem_op;    0:等到信号量为0    <0:信号量减    >0:信号量加
            short sem_flg;   IPC_NOWAIT:非阻塞等待,直接结束  0:阻塞等待,直到信号量操作
        }
参数3:要操作信号灯个数

3、控制信号灯集        int semctl()

int semctl(int semid, int semnum, int cmd,....);

参数1:要控制的信号灯集
参数2:要控制的信号灯编号
参数3:控制命令    
            IPC_STAT:获取信号灯集状态 
            IPC_SET:设置信号灯状态    
            IPC_RMID:删除信号灯集(2、4参数无用)    
            GETVAL:获取指定信号量的值
            SETVAL:设置指定信号量的值
参数4:可有可无    NULL   有就是共用体类型
        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; /* Buffer for IPC_INFO (Linux-specific) */ 
        };

返回值:
成功:cmd == GETVAL  获取到的信号量的值
失败:-1

理解了上面几个函数之后,可能对上手还是有点困难,那在写一个示例进行阅读就OK了。

关于信号灯写操作

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

int main()
{
    key_t key = ftok("home/ubuntu",10);
    int shmid = shmget(key,1024,0666 | IPC_CREAT);    //创建一个共享内存
    if (shmid <0)
    {
        perror("create errorr\");
        return -1;
    }
    key = ftok("home/ubuntu",20);
    int semid = semget(key,1,0666|IPC_CREA)//创建一个信号灯集,信号量就1个

    char *p = shmat(shmid,NULL,0);//将共享内存映射到进程的地址中,权限读写
    struct sembuf sem;
    semctl(sembuf,0,SETVAL,0);

    while(1)
    {
       	sem.sem_num = 0;
        sem.sem_op = 0;
        sem.sem_flg = 0;
		semop(semid,&sem,1);//等待信号灯值变为0

		fgets(p,1024,stdin);//把数据写入到共享内存
		//生产者 信号量++
		sem.sem_num = 0;
		sem.sem_op = 1;
		sem.sem_flg = 0;

		semop(semid,&sem,1);
		if(strcmp(p,"quit\n")==0)
		{
			break;
		} 
    }
    shmdt(p);
    shmctl(shmid,IPC_RMID,NULL);
    semctl(semid,0,IPC_RMID);
    return 0;
}

信号灯读操作,和写差距不大

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

int main()
{
	
	key_t key = ftok("/home/ubuntu",10);//计算出key值,应该和创建的进程使用的key一致
	int shmid = shmget(key,1024,0666 | IPC_CREAT);//创建 打开共享内存,得到标识
	if(shmid < 0)
	{
		perror("shm get error");
		return -1;
	}
	key = ftok("/home/ubuntu",20);//计算出key值
    int semid = semget(key,1,0666 | IPC_CREAT);

	char * p = shmat(shmid,NULL,0);

	struct sembuf sem;

	sem.sem_num = 0;
    sem.sem_op = -1;
    sem.sem_flg = 0;

	while(1)
	{
		//消费者操作 --
		semop(semid,&sem,1);	
	
		if(strcmp(p,"quit\n") == 0)
		{
			break;
		}
		printf("%s",p);
		sleep(1);
	}
	shmdt(p);
	shmctl(shmid,IPC_RMID,NULL);
	semctl(semid,0,IPC_RMID);
	return 0;
}

在进程间通信的时候,需要将读程序和写程序都要进行运行才可以,否则不会进行工作。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

啵啵520520

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值