《Linux 编程 c》学习笔记--IPC

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_32095699/article/details/88632681

IPC包括:消息队列、信号量、共享内存

IPC特点:

1.IPC由内核维护,存放在内核中

1.随内核持续,IPC不会自我删除,停止使用的IPC结构会一直保存在内核中,直到内核重启或者显示删除该对象。

关键字 key_t:唯一标识一个IPC,可以由ftok()函数生成


消息队列:

创建消息队列

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdlib.h>
int main(int argc, char const *argv[])
{
	int qid;
	key_t key;
	if(argc<2){
		printf("wrong parameters\n");
		exit(0);
	}
	key = ftok(*(argv+1),'a');
	if(key<0){
		printf("fail to get key!\n");
		exit(0);
	}

	qid = msgget(key,IPC_CREAT|0666);
	if(qid<0){
		printf("fail to create queue\n");
		exit(0);
	}
	else{
		printf("create msg queue!\n");
	}

	return 0;
}

key_t ftok(const char *pathname,int proj_id);

通过ftok来创建关键字,不同的路径会生成不同的消息队列的key_t值,ftok返回的key值是根据文件的物理索引创建的。

在两个路径下创建了两个消息队列的key值,注意消息队列位于内核中,只不过其key值由文件路径绑定!

 ipcs -q

--------- 消息队列 -----------
键        msqid      拥有者  权限     已用字节数 消息      
0x610718eb 65536      dxt        666        0            0           
0x610718e8 98305      dxt        666        0            0           

消息队列的控制

int msgctl(int maqid,int cmd,struct msqid_ds *buf);

cmd:
IPC_STAT: 在内核取此队列的msqid_ds结构, 并将它存放在buf指向的结构中. 
IPC_SET: 按由buf指向结构中的值, 设置与此队列相关结构中的msg_perm.uid, msg_perm.gid, msg_perm.mode和msg_qbytes. (该命令只有下列两种进程可以执行: (1)有效用户ID等于msg_perm.cuid或msg_per.uid. (2)具有超级用户特权的进程. )
IPC_RMID: 从系统中删除该消息队列以及仍在该队列中的所有数据. 执行权限同上.
 

发送消息:

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdlib.h>
#include <string.h>
struct my_msg
{
	long int msg_type;
	char text[BUFSIZ];
}msgbuf;


int main(int argc, char const *argv[])
{
	int msgid;

	int isrunnig=1;
	msgid = msgget((key_t)1234,IPC_CREAT|0666);
	if(msgid<0){
		printf("fail to create queue\n");
		exit(0);
	}
	else{
		printf("create msg queue!\n");
	}

	while(isrunnig){
		printf("input msg you want to send:\n");
		
		
		fgets(msgbuf.text,BUFSIZ,stdin);
		msgbuf.msg_type =1;
		
		if(msgsnd(msgid,(void*)&msgbuf,BUFSIZ,0)==-1){
			perror("sending failed....");
			exit(0);
		}
		else{
			printf("already send\n");
		}
		if(strncmp(msgbuf.text,"end",3)==0){
			printf("rec end\n");
			isrunnig=0;
		}
	}

	return 0;
}

接收消息:

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdlib.h>
#include <string.h>
struct my_msg
{
	long int msg_type;
	char text[BUFSIZ];
}msgbuf;


int main(int argc, char const *argv[])
{
	int msgid;
	long int msg_to_recv=0;

	msgid = msgget((key_t)1234,IPC_CREAT|0666);
	if(msgid<0){
		printf("fail to create queue\n");
		exit(0);
	}
	else{
		printf("create msg queue!\n");
	}

	while(1){
				
		if(msgrcv(msgid,(void*)&msgbuf,BUFSIZ,msg_to_recv,0)==-1){
			perror("recv failed....");
			exit(0);
		}
		else{
			printf("the recv msg = %s\n",msgbuf.text);
		}
		if(strncmp(msgbuf.text,"end",3)==0){
			printf("rec end\n");
			break;
		}
	}

	if(msgctl(msgid,IPC_RMID,0)==1){
		perror("msgctl(IPC_RMID) fail...");
		exit(1);
	}
	return 0;
}

BUFSIZ默认大小为8192B 

只开发送进程,可以看到,发送出去的数据已经在消息队列里了:

打开接收进程:

 接收进程接收到了‘ddd',并取出了消息队列中的信息。

注意! 在接收端一定要调用删除消息队列函数:

if(msgctl(msgid,IPC_RMID,0)==1){
	perror("msgctl(IPC_RMID) fail...");
	exit(1);
}

否自消息队列是无法自己删除的:(不调用msgctl(msgid,IPC_RMID,0)的情况)


共享内存 

注意:共享内存需要信号量来同步

共享内存在解除映射时才写回文件

转自:https://blog.csdn.net/ypt523/article/details/79958188

例子:父子进程通过共享内存通信,以及用信号量同步

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

#define SHM_SIZE 1024

int main(int argc, char const *argv[])
{
	int ret,     //临时变量
	pid,         //进程id
	sme_id,        //信号量描述符
	shm_id;        //共享内存描述符
	key_t sme_key;    //信号量键值
	key_t shm_key;   //共享内存键值
	char *shmp;        //指向共享内存首地址
	struct shmid_ds dsbuf;    //共享内存信息结构变量
	struct sembuf lock={0,-1,SEM_UNDO}; //信号量上锁数组指针
	struct sembuf unlock = {0,1,SEM_UNDO|IPC_NOWAIT};//信号量解锁数组指针
	sme_key = ftok(*(argv+1),2); //
	if(sme_key<0){
		perror("ftok");
		exit(0);
	}

	sme_id = semget(sme_key,1,IPC_CREAT|0666);
	if(sme_id<0){
		perror("semget");
		exit(0);
	}
	shm_id = shmget(shm_key,SHM_SIZE,IPC_CREAT|0666);  //获取共享内存id
	if(shm_id<0){
		perror("shmget");
		exit(0);
	}

	shmp = shmat(shm_id,NULL,0); //映射共享内存
	if((int)shmp==-1){
		perror("shmat");
		exit(0);
	}


	pid=fork();
	if(pid<0){
		perror("fork");
		exit(0);
	}
	else if(pid==0){
		ret = semctl(sme_id,0,SETVAL,1);  //初始化信号量初值=1
		if(ret==-1){
			perror("ret");
			exit(0);
		}
		ret =semop(sme_id,&lock,1); //p操作
		if(ret==-1){
			perror("semop lock");
			exit(0);
		}
		sleep(4);

		strcpy(shmp,"hello\n");    //往共享内存写数据
		if(shmdt((void*)shmp)<0){    //使共享内存脱离进程地址空间
			perror("shmdt");
			exit(0);
		}

		ret =semop(sme_id,&unlock,1); //v操作
		if(ret==-1){
			perror("semop unlock");
			exit(0);
		}
	}
	else{
		sleep(1);
		ret =semop(sme_id,&lock,1);
		if(ret==-1){
			perror("semop lock");
			exit(0);
		}
		if(shmctl(shm_id,IPC_STAT,&dsbuf)<0){
			perror("shmctl");
			exit(0);
		}
		else{

			printf("get share mem info\n");
			printf("creater pid =%d\n",dsbuf.shm_cpid);
			printf("recv msg=%s\n",(char*)shmp);
		}
		if(shmdt((void*)shmp)<0){
			perror("shmdt");
			exit(0);
		}

		ret =semop(sme_id,&unlock,1);
		if(ret==-1){
			perror("semop unlock");
			exit(0);
		}
        
        //记得删除信号量和共享内存
        if(shmctl(shm_id,IPC_RMID,NULL)<0){
			perror("shmctl");
			exit(0);
		}
		ret =semctl(sme_id,0,IPC_RMID,NULL);
		if(ret==-1){
			perror("semctl");
			exit(0);
		}
	}

	return 0;
}

输出:

get share mem info
creater pid =17494
recv msg=hello

注意:与消息队列一样,父进程退出时需要删除共享内存和信号量!

否则,会看到进程退出时,共享内存和信号量仍未释放

dxt@DXT:~/Desktop/SHI_XI/msgque$ ipcs -m

------------ 共享内存段 --------------
键        shmid      拥有者  权限     字节     连接数  状态    

0x2f2f2f2f 29425693   dxt        666        1024       0               

dxt@DXT:~/Desktop/SHI_XI/msgque$ ipcs -s

--------- 信号量数组 -----------
键        semid      拥有者  权限     nsems     
0x020718f1 0          dxt        666        1 

猜你喜欢

转载自blog.csdn.net/qq_32095699/article/details/88632681