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

15 篇文章 0 订阅

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 


就以两个不相关的进程来说明进程间 如何通过共享 内存来进行通信 。 其中 一个文
件 consumer.cpp 创建共享内存,并读取其中的信息 ,另 一个文件 producer.cpp 向共享 内存中
写人数据 。结构 shared_use_st 中的 written 作为一个可读或可写的标志,非 0 表示可读, 0
表示可写, text 则是 内存中的文件 。

producer.cpp 



#include<sys/shm.h>
#define TEXT_SIZE 2048
struct shared_use_st{
    int written;
    char text[TEXT_SIZE];
};
#include<unistd.h>
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#include<sys/shm.h>

#define CHECK(x,...) if(x==-1){fprintf(stderr,__VA_ARGS__);exit(EXIT_FAILURE);}
#define CHECK_MEM(x,...) if(x==(void*)-1){fprintf(stderr,__VA_ARGS__);exit(EXIT_FAILURE);}

int main(){

    int shmid;
    shmid = shmget((key_t)1234,sizeof(shared_use_st),0666|IPC_CREAT);
    CHECK(shmid,"falied to get share memory")
    void* shared_memory = (void*)0;
    shared_memory = shmat(shmid,(void*)0,0);
    CHECK_MEM(shared_memory,"shmat fail")
    struct shared_use_st *share_stuff;
    share_stuff = (struct shared_use_st*)shared_memory;
    int running=1;
    char buffer[BUFSIZ];
    while(running){
        while(share_stuff->written==1){
            sleep(1);
            printf("waiting for client ...\n");
        }
        printf("Enter some text\n");
        fgets(buffer,BUFSIZ,stdin);
        strncpy(share_stuff->text , buffer,TEXT_SIZE) ;
        share_stuff->written = 1;
        if (strncmp(buffer,"end",3) == 0) {
        running = 0;
    }
    }
    CHECK(shmdt(shared_memory),"shmdt failed\n")
    exit(EXIT_SUCCESS);
}

consumer.cpp


#include<sys/shm.h>
#define TEXT_SIZE 2048
struct shared_use_st{
    int written;
    char text[TEXT_SIZE];
};
#include<unistd.h>
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#include<sys/shm.h>
#include<iostream>
#define CHECK(x,...) if(x==-1){fprintf(stderr,__VA_ARGS__);exit(EXIT_FAILURE);}
#define CHECK_MEM(x,...) if(x==(void*)-1){fprintf(stderr,__VA_ARGS__);exit(EXIT_FAILURE);}

int main(){

    int shmid;
    shmid = shmget((key_t)1234,sizeof(shared_use_st),0666|IPC_CREAT);
    CHECK(shmid,"shmid failed")
    void* share_memory = (void*)0;
    share_memory = shmat(shmid,(void*)0,0);
    CHECK_MEM(share_memory,"shmat failed");
    printf("Memery attached at %X \n",(long)share_memory);
    struct shared_use_st *shared_stuff;
    shared_stuff=(struct shared_use_st *)share_memory;

    shared_stuff->written = 0;
    int running = 1;
    while(running){
        printf("shared_stuff->written:%d\n",shared_stuff->written);
        if(shared_stuff->written){

            printf("you write %s",shared_stuff->text);
            sleep(rand()%4);
            shared_stuff->written=0;
            if(strncmp(shared_stuff->text,"end",3)==0)
                running = 0;
        }


    }
    CHECK(shmdt(share_memory),"shmdt failed")
    CHECK(shmctl(shmid,IPC_RMID,0),"shmctl(shmid,IPC_RMID,0) failed")

    exit(EXIT_SUCCESS);

}

共享内存为    share_stuff  = (struct shared_use_st*)shared_memory;


 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
B站上的韩顺平老师的《Linux学习笔记》系列课程非常值得推荐。通过这个课程,我学到了很多关于Linux操作系统的知识和技能。 首先,韩老师在课程中详细介绍了Linux的基本概念和特点。我清楚地了解到Linux是一个开源的操作系统,具有稳定性、安全性和可定制性强的特点。这让我对Linux有了更深入的理解,也更有信心去学习和使用它。 其次,韩老师从基础开始,逐步讲解了Linux的安装和配置。他用简单明了的语言和实际操作的示范,帮助我了解了如何在虚拟机上安装Linux系统,并设置网络、用户账户、文件系统等。这为我后续的学习和实践打下了坚实的基础。 此外,韩老师还讲解了Linux的常用命令和工具。他详细介绍了常用的文件和目录操作命令,比如cd、ls、mkdir、cp等。同时,他还讲解了grep、sed、awk等强大的文本处理工具的使用方法。这些内容帮助我更加高效地进行文件管理和数据处理。 最后,韩老师还介绍了Linux的网络管理和安全防护。他讲解了如何配置网络连接、使用ssh远程登录以及设置防火墙等内容。这些知识对我了解网络和保护系统安全非常有帮助。 总的来说,韩顺平老师的《Linux学习笔记》课程非常实用,对于初学者来说是入门学习Linux的好选择。他通过深入浅出的讲解和丰富的实操示范,让我可以轻松地学习Linux的基本知识和操作技巧。我相信通过学习这个课程,我会在Linux领域有更进一步的发展。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值