day7:消息队列与共享内存

思维导图:

day7:消息队列与共享内存_第1张图片

消息队列原理:

day7:消息队列与共享内存_第2张图片

进程在内核空间中维护出消息队列,每个进程借由消息队列的msgid对消息队列进行读写操作,消息队列中的信息是一个结构体,存储着消息的种类(身份证)和消息的内容,多个进程间可以通过消息的种类来进行通讯,例如:进程A放了一个种类为A的信息,进程B只读取种类为A的信息,通过这种方式实现了进程间的定向信息传输。

共享内存原理:

day7:消息队列与共享内存_第3张图片

共享内存第一步是先将一块物理内存映射到内核空间,在内核空间维护出一块共享内存,然后每个进程可以通过指针的方式共同访问这块内存空间,并进行读写操作,实现进程通信。类似malloc用法。

使用消息列队实现两个进程间接受发送信息

发送端:

#include 
typedef struct m
{
	long type;
	char text[1024];
}sake;
#define SIZE sizeof(struct m)-sizeof(long)
int main(int argc, const char *argv[])
{	
	key_t key;
	if((key=ftok("/",'a'))==-1)
	{
		perror("");
		return -1;
	}
	int msgid=0;
	if((msgid=msgget(key,IPC_CREAT|0664))==-1)
	{
		perror("");
		return -1;
	}

	pid_t pid;
	pid=fork();
	if(pid>0)
	{
		sake message;
		while(1)
		{	

			message.type=1;
			printf("传送的信息:");
			scanf("%s",message.text);
			printf("%s\n",message.text);
			msgsnd(msgid,&message,SIZE,0);
			if(strcmp(message.text,"quit")==0)
			{
				break;
			}
		}

	}
	else if(pid==0)
	{

		sake message;
		while(1)
		{	
			msgrcv(msgid,&message,SIZE,2,0);
			if(strcmp(message.text,"quit")==0)
			{
				break;
			}
			printf("接收到的消息为:%s\n",message.text);
		}
	}

	return 0;
}

接收端:

#include 
typedef struct m
{
	long type;
	char text[1024];
}sake;
#define SIZE sizeof(sake)-sizeof(long)
int main(int argc, const char *argv[])
{
	key_t key;
	if((key=ftok("/",'a'))==-1)
	{
		perror("");
		return -1;
	}
	int msgid;
	if((msgid=msgget(key,IPC_CREAT|0664))==-1)
	{
		perror("");
		return -1;
	}
	pid_t pid;
	pid=fork();
	if(pid>0)
	{

		sake message;
		while(1)
		{	
			message.type=2;
			printf("传送的信息:");
			scanf("%s",message.text);
			msgsnd(msgid,&message,SIZE,0);
			if(strcmp(message.text,"quit")==0)
			{
				break;
			}
		}

	}
	else if(pid==0)
	{

		sake message;
		while(1)
		{	
			msgrcv(msgid,&message,SIZE,1,0);
			if(strcmp(message.text,"quit")==0)
			{
				break;
			}
			printf("接收到的消息为:%s\n",message.text);
		}
	}
	if(msgctl(msgid,IPC_RMID,NULL)==-1)
	{
		perror("");
		return -1;
	}

	return 0;
}

day7:消息队列与共享内存_第4张图片

复现消息列队代码:

发送端:

#include 
typedef struct message
{
	long mtype;
	char mtext[1024];
}sake;
#define SIZE sizeof(sake)-sizeof(long)
int main(int argc, const char *argv[])
{
	key_t key;
	if((key=ftok("/",'a'))==-1)
	{
		perror("");
		return -1;
	}
	int msgq=0;
	if((msgq=msgget(key,IPC_CREAT|0664))==-1)
	{
		perror("");
		return -1;
	}
	sake msg;
	while(1)
	{
		long mt=0;
		printf("请输入消息类型:");
		scanf("%ld",&mt);
		msg.mtype=mt;
		char buf[1024];
		printf("请输入发送的消息:");
		scanf("%s",buf);
		strcpy(msg.mtext,buf);
		msgsnd(msgq,&msg,SIZE,0);
		printf("operation success\n");
	}
	if(msgctl(msgq,IPC_RMID,NULL)==-1)
	{
		printf("error\n");
		return -1;
	}
	return 0;
}

接收端:

#include 
typedef struct message
{
	long mtype;
	char mtext[1024];
}sake;
#define SIZE sizeof(sake)-sizeof(long)
int main(int argc, const char *argv[])
{
	key_t key;
	if((key=ftok("/",'a'))==-1)
	{
		perror("");
		return -1;
	}
	int msgq=0;
	if((msgq=msgget(key,IPC_CREAT|0664))==-1)
	{
		perror("");
		return -1;
	}
	sake msg;
	while(1)
	{
		msgrcv(msgq,&msg,SIZE,1,0);
		printf("收到的数据为:%s\n",msg.mtext);
	}
	return 0;
}

day7:消息队列与共享内存_第5张图片

复现共享内存代码

发送端:

#include 
#define PAGE_SIZE 4096
int main(int argc, const char *argv[])
{
	key_t key;
	if((key=ftok("/",'a'))==-1)
	{
		perror("");
		return -1;
	}
	int shmid;
	if((shmid=shmget(key,4096,IPC_CREAT|0664))==-1)
	{
		perror("");
		return -1;
	}
	char *ptr=NULL;
	ptr=(char *)shmat(shmid,NULL,0);
	while(1)
	{

		fgets(ptr,PAGE_SIZE,stdin);
		ptr[strlen(ptr)-1]='\0';
		if(strcmp(ptr,"quit")==0)
		{
			break;
		}
	}
	if(shmdt(ptr)==-1)
	{
		perror("");
		return -1;
	}
	if(shmctl(shmid,IPC_RMID,NULL)==-1)
	{
		perror("");
		return -1;
	}

	return 0;
}

接收端:

#include 
#define PAGE_SIZE 4096
int main(int argc, const char *argv[])
{
	key_t key;
	if((key=ftok("/",'a'))==-1)
	{
		perror("");
		return -1;
	}
	int shmid;
	if((shmid=shmget(key,4096,IPC_CREAT|0664))==-1)
	{
		perror("");
		return -1;
	}
	char *ptr=NULL;
	ptr=(char *)shmat(shmid,NULL,0);
	while(1)
	{
		printf("收到的数据为%s\n",ptr);
		sleep(3);
		if(strcmp(ptr,"quit")==0)
		{
			break;
		}
	}
	if(shmdt(ptr)==-1)
	{
		perror("");
		return -1;
	}


	return 0;
}

day7:消息队列与共享内存_第6张图片

面试题整理:

进程和线程的区别是什么:

相同点:他们都遵循时间片轮询,上下文切换原则,

不同点:进程是资源分配的最小单位,线程是任务执行的最小单位

                在一个进程中的线程共享进程的资源,而进程之间相互独立

                线程是进程的执行单元,一个进程可以包含多个线程

如何在Linux系统中实现同步

实现同步的方式主要有两种,一种是无名信号量。无名信号量本质上是个临界资源,所有线程在执行前会去访问自己对应的无名信号量,在别的线程将自己的无名信号量增加后方可执行。

第二种是同步互斥机制中的条件变量,它结合了互斥锁思想,所有线程先获取锁资源,然后进入到消息队列后将锁资源打开供其他线程进入队列,等到条件变量被唤醒,再同时让所有再队列中的线程去获取锁资源

互斥的概念及实现

互斥指同一时刻只有一个线程可以执行,没有先后顺序,谁抢到资源谁先执行

主要依靠互斥锁进行工作,互斥锁本质上是个临界资源,所有线程再执行前先访问锁资源,访问到了便将其上锁,其他线程无法访问到锁资源。等到线程结束再释放锁资源供下次争抢。

fork()调用后,父进程和子进程的执行顺序是什么样的,他们如何共享资源

没有执行顺序,遵循时间片轮询上下文切换原则

子进程会拷贝父进程的资源,在fork语句之前的资源子进程都能使用,且相互独立

什么是僵尸进程?如何避免?

僵尸进程是指子进程已经结束但是父进程未回收其资源

可以利用signal函数,当子进程结束后,子进程会对父进程发送SIG_CHLD信号,父进程可以利用signal函数捕获这种信号,然后利用回调函数回收子进程资源。

Linux中进程间的通信方式

无名管道,有名管道,信号

消息队列,共享内存,信号量(信号灯集)

套接字

你可能感兴趣的:(IO进程线程,linux)