共享内存-父子进程、非亲缘关系进程通信

共享内存的特点:
共享内存创建后一直存在于内核中,直到被删除或系统关闭;
共享内存和管道不一样,读取后,内容仍然存在。

shm_get函数: 共享内存的创建
头文件: #include <sys/types.h>
     #include <sys/ipc.h>
     #include <sys/shm.h>
函数原型: int shmget(key_t key, int size, int shmflg)
函数参数: key:IPC_PRIVATE 或 ftok的返回值
      size:共享内存区大小
      shmflg:同open函数的权限位,也可以用8进制表示
返回: 成功:共享内存段标识符,ID,文件描述符
    失败:-1
查看IPC对象:ipcs -m 共享内存/ -p 消息队列/ -s 信号灯
删除IPC对象:ipcrm -m/-p/-s id
例:shmid=shmget(IPC_PRIVATE,128,0777);

使用shmget函数创建共享内存时,参数如果是IPC_PRIVATE,则共享内存的key值都一样,为0。如果要使key非0,则需要借助函数ftok。
ftok函数:
原型: char ftok(const char *path, char key)
参数: path:文件路径和文件名
    key:一个字符
返回值:成功返回一个key值
    失败-1
例:key=ftok("./a.c",‘b’);
  shmid=shmget(key,128,IPC_CREAT | 0777);

shmat函数: 创建了共享内存后需要将内存映射到用户空间,减少内核访问。
原型:void *shmat(int shmid, const void *shmaddr, int shmflg) //类似于malloc
参数: 第一个参数,ID号
    第二个参数,映射到的地址,NULL为系统自动完成的映射
    第三个参数,shmflg, SHM_RDONLY共享内存只读
          默认是0,表示可读写
返回: 成功映射后的地址
   失败NULL
例:p=(char *)shmat(shmid,NULL,0);

shmdt函数: 删除进程中的地址映射
原型: int shmdt(const void *shmaddr)
参数: shmaddr共享内存映射后的地址
返回: 成功0,出错-1
例:shmdt(p );

shmctl函数: 删除共享内存对象
原型: int shmctl(int shmid, int cmd, struct shmid_ds * buf)
参数: shmid,要操作的共享内存标识符
    cmd: IPC_STAT,获取对象属性值 //实现了命令ipcs -m
        IPC_SET,设置对象属性
        IPC_RMID,删除对象 //实现了命令ipcrm -m
    buf: 指定IPC_STAT/IPC_SET时用以保存/设置属性
返回: 成功0,出错-1
例:shmctl(shmid,IPC_RMID,NULL);

父子进程通信
  父进程完成内存映射后,等待读取用户输入信息;当输入完成后,通过kill向子进程发送SIGUSR1信号告知有消息可读,同时父进程进入睡眠状态;
   子进程完成内存映射后,就进入休眠状态;当收到信号后,进程唤醒,并从共享内存中读取信息;读取完成后向父进程发送SIGUSR2信号,告知,信息被读取,你可以继续输入了。

#include "sys/shm.h"
#include "signal.h"
#include "unistd.h"
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
void myfun(int signum)
{
  return ;
}
int main()
{
  int shmid;
  int key;
  char *p;
  int pid;
  shmid=shmget(IPC_PRIVATE,128,IPC_CREAT | 0777);
  if(shmid <0)
  {
	printf("creat share memory failure\n");
	return -1;
  }
  printf("creat share memory sucess shmid=%d\n",shmid);
 
  pid=fork();
  if(pid > 0)//parent process 
  { 
	signal(SIGUSR2,myfun);//kill默认终止进程,需加处理函数
    p=(char *)shmat(shmid,NULL,0);
    if(p == NULL)
    {
	 printf("parent process:shmat function failure\n");
	 return -3;
    }
    while(1)
    {
      //write share memory
	  printf("parent process start write share memory:\n");
      fgets(p,128,stdin);
	  kill(pid,SIGUSR1);// child process read data 
	  pause();// wait child process read
	}
  }
  if(pid == 0)//child process 
  {
	signal(SIGUSR1,myfun);
	p=(char *)shmat(shmid,NULL,0);
	if(p == NULL)
	{
     printf("child process shmat function failure\n");
	 return -3;
	}
    while(1)
	{
	 pause();// wait parent process write
     //start read share memory
     printf("share memory data:%s",p);
	 kill(getppid(),SIGUSR2);
	}
  }
  
  shmdt(p);
  shmctl(shmid,IPC_RMID,NULL);
  system("ipcs -m ");
 
  return 0;
}

执行结果:

creat share memory sucess shmid=2228235
parent process start write share memory:
hello
share memory data:hello

非亲缘关系进程通信
server

#include "sys/types.h"
#include "sys/shm.h"
#include "signal.h"
#include "unistd.h"
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
struct mybuf
{
  int pid;
  char buf[124];
};
void myfun(int signum)
{
  return ;
}
int main()
{
  int shmid;
  int key;
  struct mybuf  *p;
  int pid;
  key=ftok("./a.c",'a');
  if(key < 0)
  {
    printf("creat key failure\n");
	return -1;
  }
  printf("creat key sucess\n");
  shmid=shmget(key,128,IPC_CREAT | 0777);
  if(shmid <0)
  {
	printf("creat share memory failure\n");
	return -1;
  }
  printf("creat share memory sucess shmid=%d\n",shmid);
  
	signal(SIGUSR2,myfun);
    p=(struct mybuf *)shmat(shmid,NULL,0);
    if(p == NULL)
    {
	 printf("server process:shmat function failure\n");
	 return -3;
    }
     //get client pid
     p->pid=getpid();//write server pid to share memory
 
	 pause();//wait client read server pid;
     
	 pid=p->pid;
 
 
    //write
 
    while(1)
    {
      //write share memory
	  printf("parent process start write share memory:\n");
      fgets(p->buf,128,stdin);
	  kill(pid,SIGUSR1);// client process read data 
	  pause();// wait client process read
	}
 
  
  shmdt(p);
  shmctl(shmid,IPC_RMID,NULL);
  system("ipcs -m ");
 
  return 0;
}

运行结果

creat key sucess
creat share memory sucess shmid=2392070
parent process start write share memory:
hello

client

#include "sys/types.h"
#include "sys/shm.h"
#include "signal.h"
#include "unistd.h"
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
struct mybuf
{
  int pid;
  char buf[124];
};
void myfun(int signum)
{
  return ;
}
int main()
{
  int shmid;
  int key;
  struct mybuf  *p;
  int pid;
  key=ftok("./a.c",'a');
  if(key < 0)
  {
    printf("creat key failure\n");
	return -1;
  }
  printf("creat key sucess\n");
  shmid=shmget(key,128,IPC_CREAT | 0777);
  if(shmid <0)
  {
	printf("creat share memory failure\n");
	return -1;
  }
  printf("creat share memory sucess shmid=%d\n",shmid);
    
	signal(SIGUSR1,myfun);
    p=(struct mybuf *)shmat(shmid,NULL,0);
    if(p == NULL)
    {
	 printf("client process:shmat function failure\n");
	 return -3;
    }
     //get server pid
     //read share memory 
	 pid=p->pid;
	 //write client pid to share memory 
	 p->pid=getpid(); 
	 //kill signal
	 kill(pid,SIGUSR2);
  
    //client start read data from share memory
    while(1)
    {
	  pause();//wait server write data to share memory;
	  printf("client process receve data from share memory:%s",p->buf);//read data 
	  kill(pid,SIGUSR2);//server may write share memory
	}
 
  
  shmdt(p);
  shmctl(shmid,IPC_RMID,NULL);
  system("ipcs -m ");
 
  return 0;
}

运行结果

creat key sucess
creat share memory sucess shmid=2392070
client process receve data from share memory:hello
  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 是的,子进程和无亲缘关系的进程可以通过打开一个普通文件实现通信。这是因为普通文件只要能被访问,不论是读写,还是其他操作,都可以被任何进程访问,无论是子进程,还是无亲缘关系的进程。例如,可以通过使用C语言中的open()函数来实现,如下所示: int fd = open("file.txt", O_CREAT | O_RDWR, 0644);if (fd == -1) { // 如果文件打开失败,输出错误信息 perror("open file failed"); } ### 回答2: 思考子进程和无亲缘关系的进程是否可以通过打开一个普通文件实现通信,答案是可以的。 子进程可以通过打开一个文件来进行通信的原因在于它们共享文件描述符。在创建子进程时,子进程将继承进程的所有打开的文件描述符。因此,子进程可以通过打开同一个文件来实现通信。 而无亲缘关系的进程可以通过打开一个普通文件来实现通信的原因在于文件的共享性。普通文件是存储在磁盘上的一段数据,可以被多个进程同时进行访问。不同进程可以通过打开同一个文件,并向其读写数据,从而实现通信。 下面通过示例代码来说明如何通过打开一个普通文件实现进程通信: ```python # 进程创建一个文件并写入数据 file_path = "communication.txt" file = open(file_path, "w") file.write("Hello, child process!") file.close() # 进程创建子进程 pid = os.fork() if pid > 0: # 进程等待子进程退出,并读取子进程写入的数据 status = os.wait() file = open(file_path, "r") data = file.read() print("Parent process received:", data) file.close() else: # 子进程读取进程写入的数据,并写入自己的数据 file = open(file_path, "r") data = file.read() print("Child process received:", data) file.close() file = open(file_path, "w") file.write("Hello, parent process!") file.close() ``` 以上代码中,进程创建一个文件communication.txt并写入数据。然后创建子进程子进程读取进程写入的数据,并写入自己的数据。进程等待子进程退出后,再读取子进程写入的数据。这样就通过打开文件实现了子进程的通信。 ### 回答3: 思考子进程和无亲缘关系的进程是否可以通过打开一个普通文件实现通信,答案是肯定的。实现原因如下: 1. 文件是共享资源:文件是操作系统中的一种共享资源,可以被多个进程同时读取和写入。子进程及无亲缘关系的进程可以通过打开同一个普通文件来实现通信。 2. 文件读写操作:进程可以通过文件读取和写入的操作来进行通信。一个进程将需要传递的数据写入文件,另一个进程则可以读取该文件中的数据进行接收。 3. 文件锁定机制:操作系统提供了文件锁定机制,可以保证多个进程在同时操作一个文件时的数据一致性。使用文件锁可以防止并发写入时数据竞争问题。 下面是一个示例代码,其中包含子进程和无亲缘关系的进程通过打开一个普通文件实现通信: ```python import os # 子进程通信 pid = os.fork() if pid == 0: # 子进程写入数据到文件 with open("communication.txt", "w") as file: file.write("Hello from child process!") else: # 进程读取文件中的数据 with open("communication.txt", "r") as file: data = file.read() print(data) os.wait() # 无亲缘关系进程通信 fd = os.open("communication.txt", os.O_WRONLY | os.O_CREAT) pid = os.fork() if pid == 0: # 子进程写入数据到文件 os.write(fd, b"Hello from non-related process!") else: # 进程读取文件中的数据 os.wait() os.lseek(fd, 0, 0) data = os.read(fd, 1024) print(data.decode()) os.close(fd) os.unlink("communication.txt") ``` 在以上代码中,子进程通过一个文件 "communication.txt" 进行通信。子进程使用文件写操作将数据写入该文件,进程则使用文件读操作读取该文件中的数据,并打印出来。 同样地,无亲缘关系的进程也可以使用打开同一个文件的方式实现通信。在示例代码的后半部分,无亲缘关系的进程打开了 "communication.txt" 文件,将数据写入其中,然后再由另一个进程读取并打印出来。 需要注意的是,在使用文件进行进程间通信时,可以借助文件锁等机制确保数据的正确性和一致性。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值