IPC-共享内存
父子进程之间
#include<stdio.h>
#include<stdlib.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<string.h>
#define SHM_SIZE 1024
int main(void)
{
int shmid = shmget(IPC_PRIVATE, SHM_SIZE, 0666|IPC_CREAT);
if(shmid == -1)
{
perror("shmget");
exit(EXIT_FAILURE);
}
if(fork() > 0)
{
char *pshm = shmat(shmid, NULL, 0); // 0表示可读可写
if(pshm == (char*)-1)
{
perror("shmat");
exit(EXIT_FAILURE);
}
memset(pshm, 0, SHM_SIZE);
strncpy(pshm, "Hello world", 11);
if(-1 == shmdt(pshm))
{
perror("shmdt");
exit(EXIT_FAILURE);
}
wait(NULL);
printf("parent finish\n");
return 0;
}
sleep(1);
char *pshm = shmat(shmid, NULL, 0);
if(pshm == (char*)-1)
{
perror("shmat");
exit(EXIT_FAILURE);
}
printf("child read from shm: %s\n", pshm);
return 0;
}
非亲缘进程之间
问题描述:非亲缘进程之间,a进程给b进程通过共享内存发送数据
shmwr.c
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<unistd.h>
#define FTOKPATHNAME "./shmwr.c"
struct MSG
{
int flag;
char data[1024];
};
int main(void)
{
key_t key = ftok(FTOKPATHNAME, 'a'); //ftok获取一个唯一key,用于shmget
if(-1 == key)
{
perror("ftok");
exit(EXIT_FAILURE);
}
int shmid = shmget(key, sizeof(struct MSG), 0666|IPC_CREAT);
if(-1 == shmid)
{
perror("shmget");
exit(EXIT_FAILURE);
}
struct MSG *pmsg = (struct MSG *)shmat(shmid, NULL, 0); // 0表示可读可写
if((char*)pmsg == (char*)-1)
{
perror("shmat");
exit(EXIT_FAILURE);
}
memset(pmsg, 0, sizeof(struct MSG));
while(1)
{
if(pmsg->flag == 0)
{
int ret = read(STDIN_FILENO, pmsg->data, sizeof(pmsg->data));
if(-1 == ret)
{
perror("read");
exit(EXIT_FAILURE);
}
pmsg->flag = 1; //不能放在strncmp下面
putchar(10);
if(strncmp(pmsg->data, "over", 4) == 0)
break;
}
sleep(1);
}
if(-1 == shmdt(pmsg))
{
perror("shmdt");
exit(EXIT_FAILURE);
}
return 0;
}
shmrd.c
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<unistd.h>
#define FTOKPATHNAME "./shmwr.c"
struct MSG
{
int flag;
char data[1024];
};
int main(void)
{
key_t key = ftok(FTOKPATHNAME, 'a');
if(-1 == key)
{
perror("ftok");
exit(EXIT_FAILURE);
}
int shmid = shmget(key, sizeof(struct MSG), 0666|IPC_CREAT);
if(-1 == shmid)
{
perror("shmget");
exit(EXIT_FAILURE);
}
struct MSG *pmsg = (struct MSG *)shmat(shmid, NULL, 0);
if((char*)pmsg == (char*)-1)
{
perror("shmat");
exit(EXIT_FAILURE);
}
while(1)
{
if(pmsg->flag == 1)
{
if(strncmp(pmsg->data, "over", 4) == 0)
break;
write(STDOUT_FILENO, pmsg->data, strlen(pmsg->data));
putchar(10);
pmsg->flag = 0;
}
sleep(1);
}
if(-1 == shmdt(pmsg))
{
perror("shmdt");
exit(EXIT_FAILURE);
}
// 最后一个进程离开shmid所标识的共享内存时,把共享内存删掉。
// 如果这不是最后一个进程离开,就把该共享内存标记为删除,真正的删除在最后一个进程离开之后
if(-1 == shmctl(shmid, IPC_RMID, NULL)) // 当使用标签IPC_RMID时,第三个参数应为NULL
{
perror("shmctl");
exit(EXIT_FAILURE);
}
return 0;
}
使用共享内存的优缺点
优点:我们可以看到使用共享内存进行进程间的通信真的是非常方便,而且函数的接口也简单,数据的共享还使进程间的数据不用传送,而是直接访问内存,也加快了程序的效率。同时,它也不像匿名管道那样要求通信的进程有一定的父子关系。
缺点:共享内存没有提供同步的机制,这使得我们在使用共享内存进行进程间通信时,往往要借助其他的手段来进行进程间的同步工作。