有关与进程间通信的mmap方法以及进程间互斥锁的使用

本文介绍了如何通过mmap实现进程间的通信,包括匿名mmap和有名mmap的使用,以及如何利用互斥锁解决并发访问冲突。在匿名mmap示例中,父子进程共享内存实现计数器同步;有名mmap示例则展示了不同进程通过映射同一文件实现通信。此外,还详细讲解了如何配置互斥锁以实现进程间的同步,防止数据竞争问题。
摘要由CSDN通过智能技术生成

通过mmap实现进程间的通信需要先了解和理解存储映射I/O(Memory-mapped I/O),它是使一个磁盘文件与存储空间中的一个缓冲区相映射。于是当从缓冲区中取数据,就相当于读文件中的相应字节。与此类似,将数据存入缓冲区,则相应的字节就自动写入文件。这样,就可以在不使用read和write函数的情况下,使用地址(指针)完成I/O操作。就相当于指针直接指向文件中的字符串,直接对这个字符串更改等于更改文件。又因为不同进程是打开的同一个文件,所以映射区域也是相同的(因为是通过文件创建映射区域),所以不同进程的指针指向是相同的映射区域。


文章目录

  • mmap函数
  • 互斥锁如何在进程中使用
  • 总结


一、mmap函数

 

当使用父子(有亲缘关系)进程去使用时不需要使用到fd,因为直接将需要访问的资源定义为全局即可,所以将fd参数设置为-1。

 这是匿名mmap,只适用父子进程:我们以电影卖票机器为例,不同机器代表不同进程。

#include <stdio.h>
#include <sys/mman.h>
#include <pthread.h>
#include <unistd.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/wait.h>


struct mt
{
	int num;
};

int main(int argc, const char *argv[])
{
	pid_t pid;
	struct mt *mm;
	mm = mmap(NULL,sizeof(*mm),PROT_READ|PROT_WRITE,MAP_SHARED|MAP_ANON,-1,0);
//注意参数!!!!!!!!!
	if(mm == MAP_FAILED)
	{
		perror("FAIL mmap");
		return -1;
	}
	mm->num = 0;
	pid = fork();
	if(pid < 0)
	{
		return -1;
	}
	else if(pid == 0)//子,负责售票
	{
		while(mm->num < 10)
		{
			mm->num = mm->num+1;
			printf("第一台机器卖出一张,现在卖出个数为%d\n",mm->num);
			sleep(1);
		}
		exit(1);
	}
	else
	{
		while(mm->num < 10)
		{
			sleep(1);
			mm->num = mm->num+1;
			printf("第二台卖出一张,当前卖出个数为%d\n",mm->num);
		}
		exit(1);
	}
	wait(NULL);
	return 0;
}

这样就实现了父子进程共享一个num。

以下为有名mmap,可以应用于无亲缘关系的进程:注意参数:fd这里就需要使用了,因为是不同程序访问相同文件。

#include <stdio.h>
#include <sys/mman.h>
#include <pthread.h>
#include <unistd.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <string.h>


int main(int argc, const char *argv[])
{
	int i = 0;
	char *p = NULL;
	int fd = open("mmap_test.txt",O_CREAT|O_RDWR,0777);
	if(fd < 0)
	{
		perror("FAIL open");
		return -1;
	}
	lseek(fd,200,SEEK_END);
	write(fd,"\0",1);//将文件大小变为201,为了计算映射空间大小
	int len = lseek(fd,0,SEEK_END);
	lseek(fd,0,SEEK_SET);
	p = mmap(NULL,len,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
	if(p == MAP_FAILED)
	{
		perror("FAIL mmap");
		return -1;
	}
	
		while(i++ < 100)
		{
			strcpy(p,"hello");
			printf("这是写,当前大小为%s\n",p);
			sleep(1);
		}
	close(fd);
    free(p);
	return 0;
}

这是个写文件,是个进程,再写一个读文件当做另一个进程(读文件只printf不更改值),开始时读文件为空白,但是在写文件运行后,读文件也开始输出hello,说明指针确实都指向了同一个区域,并且更改成功了。

在上述匿名mmap例子时,可能会发现第一台机器在卖时,第二台也在卖,假如我们不允许同时卖,这样的话就可以通过互斥锁将将两个进程在访问num时锁起来,但是互斥锁一般用于线程,但是这里用于进程,怎么办呢?看我如何实现它。

二、互斥锁如何在进程中使用

互斥锁的属性是可以更改的

初始化互斥锁

pthread_mutex_init()

int pthread_mutex_init(pthread_mutex_t *restrict mutex,const pthread_mutexattr_t *restrict attr);

功能:  初始化一把锁

参数:

@mutex 要初始化的锁

@attr  NULL (锁的属性) (NULL默认属性的锁)

返回值:

成功 返回0

失败 返回错误码

<2>初始化互斥锁

pthread_mutex_init()

int pthread_mutex_init(pthread_mutex_t *restrict mutex,const pthread_mutexattr_t *restrict attr);

功能:  初始化一把锁

参数:

@mutex 要初始化的锁

@attr  NULL (锁的属性) (NULL默认属性的锁)

返回值:

成功 返回0

失败 返回错误码

pthread_mutex默认是线程间通信加的锁,要是想用在进程之间,需要pthread_mutexattr_t *restrict attr 填充这个字段,在属性字段当中修改为PTHREAD_PROCESS_SHARED标识进程间共享。也是定义一个互斥锁的属性,更改属性,将这个属性赋予互斥锁,那么这个锁就可以进行进程间的通信了。最后记得销毁互斥锁及其属性。

pthread_mutexattr_init(&mm->mutexattr);        
  // 初始化 mutex 属性
 pthread_mutexattr_setpshared(&mm->mutexattr, PTHREAD_PROCESS_SHARED);               
 // 修改属性为进程间共享
 
pthread_mutex_init(&mm->mutex,&mm->mutexattr);      
// 初始化一把 mutex 锁
struct mt
{
	int num;
	pthread_mutex_t mutex;
	pthread_mutexattr_t mutexattr; 
};
int main(int argc, const char *argv[])
{
	pid_t pid;
	struct mt *mm;
	mm = mmap(NULL,sizeof(*mm),PROT_READ|PROT_WRITE,MAP_SHARED|MAP_ANON,-1,0);
	if(mm == MAP_FAILED)
	{
		perror("FAIL mmap");
		return -1;
	}
	mm->num = 0;
	pthread_mutexattr_init(&mm->mutexattr);//初始化mutex属性
	pthread_mutexattr_setpshared(&mm->mutexattr,PTHREAD_PROCESS_SHARED);
	pthread_mutex_init(&mm->mutex,&mm->mutexattr);//初始化一把锁

	pid = fork();
	if(pid < 0)
	{
		return -1;
	}
	else if(pid == 0)//子,负责售票
	{
		while(mm->num < 10)
		{
			pthread_mutex_lock(&mm->mutex);
			mm->num = mm->num+1;
			printf("儿子卖出一张,现在卖出个数为%d\n",mm->num);
			pthread_mutex_unlock(&mm->mutex);
			sleep(1);
		}
		exit(1);
	}
	else
	{
		while(mm->num < 10)
		{
			sleep(1);
			pthread_mutex_lock(&mm->mutex);
			mm->num = mm->num+1;
			printf("父亲卖出一张,当前卖出个数为%d\n",mm->num);
			pthread_mutex_unlock(&mm->mutex);
		}
		exit(1);
	}
	wait(NULL);
	pthread_mutexattr_destroy(&mm->mutexattr);//销毁锁的属性对象
	pthread_mutex_destroy(&mm->mutex);//销毁锁
	return 0;
}

 


总结

匿名可以使用互斥锁,那么有名同样可以使用,因为锁的是文件资源。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值