linux_共享存储映射区-mmap函数-munmap函数-进程通信-strace命令

接上一篇:linux_FIFO命名管道-mkfifo函数-进程通信

今天来分享linux的共享映射区,主要就是mmap函数和munmap函数的使用,话不多说,上菜:

1.共享存储映射I/O

  共享存储映射I/O就是使一个磁盘文件与存储空间中的一个缓冲区相映射,当从缓冲区中取数据,就相当于读文件中的相应字节;将数据存入缓冲区,则相应的字节就自动写入文件。
使用这种方法,就需要用到两个函数,mmap和munmap函数

2.mmap函数

函数作用:
  创建的映射区首地址。
头文件:
  #include <sys/mman.h>
函数原型:
  void *mmap(void *adrr, size_t length, int prot, int flags, int fd, off_t offset);
函数参数:

addr: 	建立映射区的首地址,由Linux内核指定。使用时,直接传递NULL
length: 欲创建映射区的大小
prot:	映射区权限PROT_READ、PROT_WRITE、PROT_READ|PROT_WRITE
flags:	标志位参数(常用于设定更新物理区域、设置共享、创建匿名映射区)
	  	MAP_SHARED:  会将映射区所做的操作反映到物理设备(磁盘)上。
	  	MAP_PRIVATE: 映射区所做的修改不会反映到物理设备。
fd: 	用来建立映射区的文件描述符
offset:映射文件的偏移(4k的整数倍)
		为什么是4k的整数倍,因为mmu创建的映射区,mmu的最小单位是4k

返回值:
  成功:返回创建的映射区首地址;
  失败:返回MAP_FAILED宏

3.munmap函数

函数作用:
  删除指定地址范围的映射。
头文件:
  #include <sys/mman.h>
函数原型:
  int munmap(void *addr, size_t length);
函数参数:
  addr:映射区首地址
  length:映射区大小
返回值:
  成功:0;
  失败:-1
注意:
  ①当进程终止时,区域也会自动取消映射;
   ②若fd存在,手动关闭文件描述符不会取消映射该区域。

4.例子:模拟malloc函数实现

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>

void *Malloc(size_t size)
{
	void *p = NULL;
	p = mmap(NULL, size, PROT_READ|PROT_WRITE, 
			MAP_SHARED | MAP_ANONYMOUS, -1, 0);//MAP_ANONYMOUS必须加上,或加上MAP_ANON
	if (p == MAP_FAILED) 
    {		
		p = NULL;
        perror("mmap failed");
        exit(1);
	}
	return p;
}

void Free(void *ptr, size_t size)
{
	munmap(ptr, size);//删除分配的映射区
}
int main(void)
{
	int *p = NULL;
	pid_t pid;
	
	p = (int *)Malloc(40);

	pid = fork();				//创建子进程
	if (pid == 0) 
	{
		p[0] = 2000;
        p[1] = 3000;
		printf("子进程: p[0] = %d p[1] = %d\n", *p,p[1]);
	} 
	else 
	{
		sleep(1);
		printf("父进程: p[0] = %d p[1] = %d\n", *p,p[1]);
	}
	Free(p, 4);
	return 0;
}

5.例子:使用文件创建映射区

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

int main(void)
{
    char *pbuf = NULL;
    int fd = open("hello", O_RDWR|O_CREAT|O_TRUNC, 0644);//读写、文件不存在则创建,文件存在则截断
    if (fd < 0)
    {
        perror("open error");
        exit(1);
    }

    ftruncate(fd, 20);//文件拓展20个字节

    pbuf = mmap(NULL, 20, PROT_WRITE, MAP_SHARED, fd, 0);
    if (pbuf == MAP_FAILED)
    {
        perror("map error");
        exit(1);
    }
    close(fd);
    strcpy(pbuf, "hello friend!");//复制字符串到pbuf中
    printf("%s\n", pbuf);

    if (munmap(pbuf,  4) < 0)
    {
        perror("munmap error");
        exit(1);
    }
    return 0;
}

6.例子:使用映射区进行父子进程通信

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/wait.h>
int var = 15;
int main(void)
{
    int *p = NULL;
    pid_t pid;

    int fd;
    fd = open("hello", O_RDWR|O_CREAT|O_TRUNC, 0644);//读写、文件不存在则创建,文件存在则截断
    if(fd < 0)
    {
        perror("open error");
        exit(1);
    }
    unlink("hello");				//删除临时文件目录项,使之具备被释放条件.
    ftruncate(fd, 4);
    //p = (int *)mmap(NULL, 4, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
    p = (int *)mmap(NULL, 4, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);//MAP_SHARED父子进程共享映射区
    if(p == MAP_FAILED)
    {		
        //注意:不是p == NULL
        perror("mmap error");
        exit(1);
    }
    close(fd);					//映射区建立完毕,即可关闭文件

    pid = fork();				//创建子进程
    if(pid == 0)
    {
        *p = 2000;
        var = 188;
        printf("子进程: *p = %d, var = %d\n", *p, var);
    } 
    else 
    {
        sleep(1);
        printf("父进程: *p = %d, var = %d\n", *p, var);
        wait(NULL);

        int ret = munmap(p, 4);				//释放映射区
        if (ret == -1) 
        {
            perror("munmap error");
            exit(1);
        }
    }

    return 0;
}

7.例子:创建匿名映射区

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
int main(void)
{
	int *p;
	pid_t pid;
	p = mmap(NULL, 4, PROT_READ|PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0); //MAP_ANONYMOUS必须加上,或加上MAP_ANON,虽然可能找不到该宏
	if(p == MAP_FAILED)
	{		
		//注意:不是p == NULL
		perror("mmap error");
		exit(1);
	}
	pid = fork();				//创建子进程
	if(pid == 0)
	{
		*p = 2000;
		printf("子进程:*p = %d\n", *p);
	} 
	else 
	{
		sleep(1);
		printf("父进程:*p = %d\n", *p);
	}
	munmap(p, 4);				//释放映射区
	return 0;
}

8.strace命令使用

  strace +可执行文件 #可以追踪该程序调用哪些函数
例如:
  strace ./test1 #追踪test1可执行文件调用了哪些函数

以上就是本次的分享了,希望能对大家有所帮助。

此博主在CSDN发布的文章目录:【我的CSDN目录,作为博主在CSDN上发布的文章类型导读

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

futureCode.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值