Linux系统编程阶段:多进程间通信,IPC机制(二)信号量和消息队列相关知识和函数。

一、信号量

1.作用:解决多个进程间的同步与互斥,可以用信号量。

2.信号量:本质是一个数字,这个数字可以进行加或者减的操作,对应的是P,V操作。消耗/获得信号量(-1),对应p操作;释放信号量(+1),对应v操作。信号量变为0后,其他进程想要消耗信号量就会被阻塞。

3.使用流程:

        1)创建信号集;

        2)初始化信号集中的每个信号值;

        3)需要保护的临界代码前进行 P 操作;

        4)执行完成临界代码后进行 V 操作;

        5)不需要的话删除信号集。

4.相关函数

semget():信号量的创建或者打开

        原型:int semget(key_t key, int nsems, int semflg);

        头文件:

                #include <sys/types.h>

                #include <sys/ipc.h>

                #include <sys/sem.h>

        参数:

                key_t key:键值

                int nsems:要创建的信号的个数  一般写1  

                int semflg:标志    IPC_CREAT | 0644

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

                     信号默认值为 0

semctl():设置/删除信号量

        原型:int semctl(int semid, int semnum, int cmd, ...);

        头文件:

                #include <sys/types.h>

               #include <sys/ipc.h>

              #include <sys/sem.h>

        参数:

                int semid:信号量的id

                int semnum:信号量的下标  一般写0

                int cmd:SETVAL:设置信号量

                IPC_RMID:删除信号量

                ...:假如CMD为IPC_RMID,后边则没有参数

                      假如CMD为SETVAL时,设置信号量,SETVAL  后边跟几,就是设置几个信号量,需要传入一个共用体。

                union semun {

                                  int val;   //给信号量赋的初值

                                  struct semid_ds *buf;

                                  unsigned short *array;

                                  struct seminfo *_buf;

                                 };

        返回值:成功,0   失败, -1

semop():消耗/释放一个信号量

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

        头文件:

                #include <sys/types.h>

                #include <sys/ipc.h>

                #include <sys/sem.h>

        参数:

                int semid:信号量的id

                sops:对信号量的操作,封装有个结构体,

                        struct sembuf myops{                   

                                   unsigned short sem_num;  // 信号量的下标 ,一般填0

                                   short sem_op;                     //要进行的操作

                                        +1:V操作 释放一个信号量

                                        -1:P操作  消耗一个信号量

                                  short  sem_flg;                  //0:表示申请不到信号量就阻塞

                                                       };                   //自己定义的

          size_t nsops:操作的信号量的个数, 一般写1

        返回值:成功返回0   失败,-1

下面是一个练习的例子:

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <unistd.h>
int main()
{
	struct sembuf myops;
	key_t keyid;
	int semid;
	int pd,i;
	pd = fork();
	if(pd == 0)
	{
	    keyid = ftok("/home/whs/002/7.5",5);
	    if(keyid<0)
	    {
		    perror("ftok");
		    return -1;
	    }
	    semid = semget(keyid,1,IPC_CREAT|0644); //信号量的创建
	    semctl(semid,0,SETVAL,1);     //信号量的设置
	    myops.sem_num=0;    //信号量的下标
	    myops.sem_op=-1;    //要进行的操作
	    myops.sem_flg=0;    //表示请不到信号就阻塞
	    semop(semid,&myops,1); //消耗一个信号量
	    for(i=0;i<5;i++)
	    {
	        printf("i=%d\n",i);
	        sleep(1);
	    }
	    myops.sem_op=1;      //释放一个信号量
	    semop(semid,&myops,1);
	}
	if(pd > 0)
	{
	    sleep(1);
	    keyid = ftok("/home/whs/002/7.5",5);
	    if(keyid<0)
	    {
		    perror("ftok");
		    return -1;
	    }
	    semid = semget(keyid,1,IPC_CREAT|0644);
	    myops.sem_num=0;
	    myops.sem_op=-1;
	    myops.sem_flg=0;
	    semop(semid,&myops,1); //消耗一个信号量
	    for(int j=0;j<5;j++)
	    {
	        printf("j=%d\n",j);
	        sleep(1);
	    }
	    myops.sem_op=1;      //释放一个信号量
	    semop(semid,&myops,1);
	}
	semctl(semid,0,IPC_RMID); //删除信号量
	return 0;
}

二、消息队列

1.特点

        先进新出

        一次性可以接收多条消息

        当有进程读消息的时候,读取的最先进队列的

2.消息队列的消息的分类

可以是1类消息、2类消息、3类消息...........

3.相关函数

msgget():创建/打开一个消息队列

        原型:int msgget(key_t key, int msgflg);

        头文件:

                #include <sys/types.h>

                #include <sys/ipc.h>

                #include <sys/msg.h>

        参数:

                key_t key:键值

                int msgflg:IPC_CREAT|0644

        返回值:成功返回消息队列id  失败返回-1

msgsnd():向消息队列发送一个消息

        原型:int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);

        头文件:

                #include <sys / types.h>

                #include <sys / ipc.h>

                #include <sys / msg.h>

        参数:

                msqid:消息队列的id

                msgp:要发送的消息的结构体

                struct msgbuf{

                        long mtype;         //消息类型----必须是long类型

                        char mtext[100]; //消息正文

                        };---需要自己定义

                msgsz:消息大小,不包括type.(sizeof(mybuf)-sizeof(long))

                msgflg:一般赋0,阻塞方式

        返回值:成功返回0  失败返回-1

msgrcv():从消息队列读取一个消息

        原型:ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);

        头文件:

                #include <sys / types.h>

                #include <sys / ipc.h>

                #include <sys / msg.h>

        参数:

                msqid:消息队列的队列 ID

                msgp:读取到的消息存放的地方的首地址(buf)

                msgsz:消息大小,不包括type,不要以 null 结尾

                msgtyp:消息类型,  =0 ,表示读取不到就阻塞;  >0 只接收指定类型的数据; <0 只接受小于等于其绝对值

                msgflg:一般赋0,阻塞方式

        返回值:接收成功返回0,失败返回-1

msgctl():消息队列的删除

        原型:msgctl(int msgid,cmd ....);

        参数:

                msgid:消息队列的id

                cmd:IPC_RMID

                NULL结尾

下面是练习的代码:

//往消息队列里面写内容
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
struct msgbuf{
    long mtype; 
    char mtext[100];
}mybuf;//要发送的消息的结构体
int main()
{
    key_t kid;
    int mid;
    kid =ftok("/home/whs/002/",6);    //设置键值
    mid = msgget(kid,IPC_CREAT|0644); //创建并打开一个消息队列
    mybuf.mtype=1;                    //消息类型设置为1类消息
    strcpy(mybuf.mtext,"hello!");     //消息里面要写到内容
    msgsnd(mid,&mybuf,sizeof(mybuf)-sizeof(long),0); //向消息队列发送一个消息
    
    return 0;
}
//从消息队列里面读取内容
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
struct msgbuf{
    long mtype;
    char mtext[100];
}mybuf;
int main()
{
    key_t kid;
    char buf[120];
    int mid;
    kid =ftok("/home/whs/002/",6);  //设置键值
    mid = msgget(kid,IPC_CREAT|0644); //打开一个消息队列
    msgrcv(mid,buf,sizeof(mybuf),1,0); //从消息队列读取一个消息
    printf("buf=%s\n",(buf+8));
    msgctl(mid,IPC_RMID,NULL);      //删除消息队列
    
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

编程小白菜123

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

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

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

打赏作者

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

抵扣说明:

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

余额充值