Linux进程间通信之《共享内存》入门
目录
简述
共享内存是Linux系统进程间通信常用的方式,通常用于数据量较大的情况,如果只是用于不同的进程间消息通知,那不如用消息队列或者socket。之前做的项目中,使用共享内存的其实只有一种情况:视频数据的共享。设备类似于DVR,视频采集编码在一个独立的程序中,另一个程序负责协议通信。
共享内存要想好用,共享的那段内存,需要用数据结构和队列组织起来,加上读写索引和数据有效标志(已读和未读、可读)。下面的这个示例代码是我初学时的,适合入门和了解使用流程。
代码
写端代码
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/ipc.h>
#include <sys/types.h>
#include <sys/shm.h>
#include <string.h>
#include <unistd.h>
#define N 1024
typedef struct
{
pid_t pid;
char text[N];
}SHMBUF;
void handler(int signo) {printf("signo=%d\n", signo);}
int main()
{
int shmid;
SHMBUF *shmadd;
key_t key;
pid_t peerpid;
if ((key = ftok(".", 'a')) == -1)
{
perror("ftok");
exit(-1);
}
signal(SIGUSR1, handler);
if ((shmid = shmget(key, sizeof(SHMBUF), 0666 | IPC_CREAT | IPC_EXCL)) == -1)
{
if (errno == EEXIST)
{
shmid = shmget(key, sizeof(SHMBUF), 0666);
if ((shmadd = (SHMBUF *)shmat(shmid, NULL, 0)) == (SHMBUF *)-1)
{
perror("shmat");
exit(-1);
}
peerpid = shmadd->pid;
shmadd->pid = getpid();
kill(peerpid, SIGUSR1);
}
else
{
perror("shmget");
exit(-1);
}
}
else //first process
{
if ((shmadd = (SHMBUF *)shmat(shmid, NULL, 0)) == (SHMBUF *)-1)
{
perror("shmat");
exit(-1);
}
shmadd->pid = getpid();
//sprintf(shmadd, "%d", getpid());
pause();
peerpid = shmadd->pid;
}
printf(">");
while (1)
{
fgets(shmadd->text, N, stdin);
shmadd->text[strlen(shmadd->text)-1] = '\0';
kill(peerpid, SIGUSR1);
if (strncmp(shmadd->text, "quit", 4) == 0)
{
sleep(1);
if (shmdt(shmadd) == -1)
{
perror("shmdt");
}
if (shmctl(shmid, IPC_RMID, NULL) == -1)
{
perror("RM");
exit(-1);
}
exit(0);
}
pause();
printf(">");
}
return 0;
}
读取端代码
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/ipc.h>
#include <sys/types.h>
#include <sys/shm.h>
#include <string.h>
#include <unistd.h>
#define N 1024
typedef struct
{
pid_t pid;
char text[N];
}SHMBUF;
void handler(int signo) {printf("signo=%d\n", signo);}
int main()
{
int shmid;
SHMBUF *shmadd;
key_t key;
pid_t peerpid;
if ((key = ftok(".", 'a')) == -1)
{
perror("ftok");
exit(-1);
}
signal(SIGUSR1, handler);
if ((shmid = shmget(key, sizeof(SHMBUF), 0666 | IPC_CREAT | IPC_EXCL)) == -1)
{
if (errno == EEXIST)
{
shmid = shmget(key, sizeof(SHMBUF), 0666);
if ((shmadd = (SHMBUF *)shmat(shmid, NULL, 0)) == (SHMBUF *)-1)
{
perror("shmat");
exit(-1);
}
peerpid = shmadd->pid;
shmadd->pid = getpid();
kill(peerpid, SIGUSR1);
}
else
{
perror("shmget");
exit(-1);
}
}
else //first process
{
if ((shmadd = (SHMBUF *)shmat(shmid, NULL, 0)) == (SHMBUF *)-1)
{
perror("shmat");
exit(-1);
}
shmadd->pid = getpid();
pause();
peerpid = shmadd->pid;
}
while (1)
{
pause();
printf("read %s\n", shmadd->text);
if (strncmp(shmadd->text, "quit", 4) == 0)
{
if (shmdt(shmadd) == -1)
{
perror("shmdt");
}
exit(0);
}
// sleep(1);
usleep(100000);
kill(peerpid, SIGUSR1);
}
exit(0);
}
编译
gcc reader.c -o reader
gcc writer.c -o writer
运行