linux多线程【8】mmap实现父子进程的共享内存通信,用信号量同步

时间:2022-11-17 15:18:15


1.创建文件。open,ftruncate

2.将文件映射到内存。内存首地址存放一个sem_t实现进程的互斥。mmap,sem_init

3.创建子进程。父子进程互斥地访问共享内存的内容。fork,sem_wait,sem_post

4.取消映射。munmap


由于需要同步或者互斥,因此需要sem_t,我们把他放在内存区的开头,那么真正可用的内存就是开头做一定偏移。维护一个指针,使指针

指向实际数据区。就定义一个结构体:

struct file_content
{
    sem_t st;
    void *pv;
} file_content;

初始化时:

 pfc->pv = (void *) ((char *) pfc + sizeof (struct file_content));     // pv指向结构体下一个字节的地址

这样,st就是sem_t信号量。pv就是数据指针,比较方便!

另外,sem_t初始化时第二个参数设为1,表示用于进程间而不限于进程间的访问。

#include <unistd.h>
#include <fcntl.h>
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <errno.h>
#include <syslog.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <semaphore.h>

struct file_content
{
    sem_t st;
    void *pv;
} file_content;


#define NINT 16
#define FILE_ "map_file"	// 映射文件
#define FILE_MODE  S_IRUSR | S_IWUSR	// 打开文件的权限mode

int
main (int argc, char *argv[])
{
    int fd;
    struct file_content *pfc;

    //打开文件
    fd = open (FILE_, O_RDWR | O_CREAT, FILE_MODE);
    if (fd == -1)
      {
	  printf ("file open failed!\n");
	  exit (2);
      }

    //将文件变为256大小
    ftruncate (fd, sizeof (file_content) + sizeof (int) * NINT);

    //内存映射
    pfc =
	mmap (NULL, sizeof (file_content) + sizeof (int) * NINT,
	      PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    if (pfc == MAP_FAILED)
      {
	  printf ("map failed!\n");
	  exit (3);
      }

    // 关闭文件
    close (fd);


    sem_init (&(pfc->st), 1, 1);		//信号两初始化为1,用于互斥
    pfc->pv = (void *) ((char *) pfc + sizeof (struct file_content));     // pv指向结构体下一个字节的地址
    printf ("结构体地址:\t\t%x\n结构体下一位置地址:\t\t%x\n", (int)pfc, (int)pfc->pv);

	setbuf(stdout,NULL); // 不加上这句的话,可能输出会卡在那里!
////////////////////////////////////////////////
    if (fork () == 0)		//子进程
      {
	  int i;
	  while (1)
	    {
		sem_wait (&(pfc->st));
		printf ("Child process\n");
		int *p = pfc->pv;
		for (i = 0; i < NINT; i++)
		  {
		      p[i] = 2 * i;
		  }
		/*
		for (i = 0; i < NINT; i++)
		  {
		      printf ("%d ", p[i]);
		  }
		printf ("\n"); */
		sem_post (&(pfc->st)); 
		usleep(2000); 
	    }
      }
    else			// 父进程
      {
	  int i;
	  while (1)
	    {
		sem_wait (&(pfc->st));
		printf ("Father process\n");
		int *p = pfc->pv;
		for (i = 0; i < NINT; i++)
		  {
		      p[i] = 3 * i;
		  }
		/*
		for (i = 0; i < NINT; i++)
		  {
		      printf ("%d ", p[i]);
		  }
		printf ("\n");
		*/
		sem_post (&(pfc->st));
		usleep(2000);
	    }
      }



////////////////////////////////////////////////

    if (munmap (pfc, sizeof (file_content) + sizeof (int) * NINT) == -1)
      {
	  printf ("ummap!\n");
	  exit (2);
      }

    return 0;
}

父子进程都是无线运行的,需要按ctrl+c退出:

administrator@ubuntu:~/test$ ./sh
结构体地址:		b7717000
结构体下一位置地址:		b7717014
Father process
Child process
Father process
Child process
Father process
Child process
Father process
Child process
Father process