目錄
簡述
共享內存是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
運行
微信公衆號