Linux学习笔记:进程间通信(消息队列和信号量)

一、消息队列

    定义

        Unix早期通信机制之一的信号能够传送的信息量有限,管道则只能传送无格式的字节流,这给程序开发带来了不便,消息队列(也叫作报文队列)则客服了这些缺点

        消息队列就是一个消息的链表,可以把消息看做一个记录,具有特定的格式,进程可以向中按照一定的规则添加新消息;另一些进程则可以从消息队列中读走消息

    分类:POSIX消息队列和系统V消息队列,后者用的多

    持续性:系统V消息队列是随内核持续的,只有内核重启或者人工删除否则消息队列一直存在

    键值

        消息队列的内核持续性要求每个消息队列都在系统范围内对应唯一的键值,所以要获得一个消息队列的描述字,必须提供该消息队列的键值

        key_t ftok(char *pathname,char proj)

        返回文件名对应的键值

        proj:项目名,不为0即可

    打开/创建

        int msgget(key_t key,int msgflg)

        key:键值,由ftok获取

        msgflg:标志位

            IPC_CREAT创建新的消息队列

            IPC_EXCL如果要创建的已经存在返回错误

            IPC_NOWAIT读写消息队列要求无法满足时不阻塞

        返回值:与键值key相对应的消息队列描述字

        将创建新消息队列的情况:如果没有与键值key相对应的消息队列并且msgflg中包含了IPC_CREAT标志位;key参数为IPC_PRIVATE

    发送消息

        int msgsnd(int msqid,struct msgbuf* msgp,int msgsz,int msgflg)

        msqid:消息队列描述符

        msgp:存放消息的结构体

        msgsz:消息数据长度

        msgflg:发送标志,有意义的msgflg标志为IPC_NOWAIT,指明在消息队列中没有足够的空间容纳要发送的消息时,msgsnd是否等待 

 struct msgbuf
{
long mtype;//消息类型
char mtext[1];//消息数据的首地址
}

    接收消息

        int msgrcv(int msqid,struct msgbuf *msgp,int msgsz,long msgtype,int msgflg)

        从 msqid代表的消息队列中读取一个msgtype类型的消息,并把消息存储在msgp所指的msgbuf结构中,在成功读取了一条消息后,队列中的这条消息将被删除

    消息队列示例程序

#include <stdio.h>
#include <sys/msg.h>
#include <unistd.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/types.h>

struct msg_buf
{
	long mtype;
	char data[255];
};


int main()
{
	key_t key;
	int msgid;
	int ret;
	struct msg_buf msgbuf;
	key=ftok("/tmp/2",'a');//获取键值
	printf("key=[%x]\n",key);
	msgid=msgget(key,IPC_CREAT|0666);//通过文件对应
	if(msgid==-1)
	{
		printf("create error\n");
		return -1;
	}
	msgbuf.mtype=getpid();
	strcpy(msgbuf.data,"test haha");//数据“test haha”
	//printf("%d\n",sizeof(msgbuf.data));//测试
	//printf("%s\n",msgbuf.data);//测试
	ret=msgsnd(msgid,&msgbuf,sizeof(msgbuf.data),IPC_NOWAIT);//发送信号
	if(ret==-1)
	{
		printf("send message error\n");
		return -1;
	}
	memset(&msgbuf,0,sizeof(msgbuf));//清空msgbuf
	ret=msgrcv(msgid,&msgbuf,sizeof(msgbuf.data),getpid(),0);//接收
	if(ret==-1)
	{
		printf("recv message error\n");
		return -1;
	}
	printf("recv msg=[%s]\n",msgbuf.data);
}

    运行结果

[gyy@localhost process_com]$ gcc msg.c -o msg
[gyy@localhost process_com]$ ./msg
key=[ffffffff]
255
test haha
recv msg=[test haha]

    代码分析:首先获取文件键值,然后创建消息队列,接下来发送消息,最后从消息队列中读出了消息,发送的和读到的相同,说明程序运行正常

六、信号量

    主要用途是保护临界资源,进程可以根据它来判断是否能够访问某些共享资源,除了用于访问控制外,还可以用于进程同步

    分类

        二值信号量:取值只有0和1,类似于互斥锁两者不同:信号量强调共享资源,只要共享资源可用,其他进程同样可以修改信号量的值;互斥锁更强调进程,占用资源的进程使用完资源后,必须由进程本身来解锁

        计数信号量:信号量的值可以去任意非负整数

    创建/打开

        #include <sys/types.h>

        #include <sys/ipc.h>

        #include <sys/sem.h>

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

        key:键值,由ftok获得

        nsems:指定打开或新创建的信号灯集中将包含信号灯的数目

        semflg:标识,同消息队列

    操作

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

        对信号量进行操作

        semid:信号量集的ID

        sops:一个操作数组,表明要进行什么操作

        nsops:sops所指向的的元素个数

struct sembuf
{
unsigned short sem_num;//在信号量集合中的第几个
short sem_op;//操作
short sem_flg;
}

        IPC_NOWAIT:同消息队列

        IPC_UNDO:程序结束时释放信号量,这样的目的在于避免程序在异常情况下结束时未将锁定的资源解锁,造成该资源永远锁定
 

猜你喜欢

转载自blog.csdn.net/a568713197/article/details/86748950
今日推荐