[置顶] Linux 下进程间通信机制(四) 共享内存 Shared Memory

用于共享内存的函数如下:

#include <sys/shm.h>
void *shmat(int shm_id, const void *shm_addr, int shmflg);
int shmctl(int shm_id, int cmd, struct shmid_ds *buf);
int shmdt(const void *shm_addr);
int shmget(key_t key, size_t size, int shmflg);

与信号量相类似,通常需要在包含shm.h文件之前包含sys/types.h与sys/ipc.h这两个头文件。



IPC操作时IPC_CREAT和IPC_EXCL选项的说明
IPC(包括消息队列,共享内存,信号量)的xxxget()创建操作时,可以指定IPC_CREAT和IPC_EXCL选项。

以共享内存为例:
当只有IPC_CREAT选项打开时,不管是否已存在该块共享内存,则都返回该共享内存的ID,若不存在则创建共享内存;
当只有IPC_EXCL选项打开时,不管有没有该快共享内存,shmget()都返回-1;
当IPC_CREAT | IPC_EXCL时, 如果没有该块共享内存,则创建,并返回共享内存ID。如果已存在,则立即返回-1,不会打开或者创建。(通常用来判断那个进程首先被打开,然后让其初始化,以后打开的进程就无需对共享内存初始化了)


demo:

利用IPC对象的共享内存机制,实现两个进程通信,用信号同步。

//writer.c
#include <stdio.h>
#include <unistd.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>

#define N 1024

typedef struct
{
    pid_t pid;  //最先打开的进程会把自己的pid记录在此,对其进行初始化
    char buf[N];
}SHM;

void handler(int signo)   //用于发给唤醒pause
{
}

int main()
{
	key_t key;
	int shmid;
	SHM *shmaddr;
	pid_t peerpid;

    signal(SIGUSR1, handler);

	if ((key = ftok(".", 'a')) == -1)
	{
		perror("ftok");
		exit(-1);
	}
 
//创建共享内存
	if ((shmid = shmget(key, sizeof(SHM), 0666 | IPC_CREAT | IPC_EXCL)) == -1)//IPC_EXCL同open的EXCL,用于判断是哪个进程最先打开
	{
		if (errno == EEXIST)
		{
			shmid = shmget(key, sizeof(SHM), 0666);
	
            if ((shmaddr = (SHM *)shmat(shmid, NULL, 0)) == (SHM *)-1)
        	{
	        	perror("shmat");
		        exit(-1);
        	}
            peerpid = shmaddr->pid;
            shmaddr->pid = getpid();
            kill(peerpid, SIGUSR1);
		}
		else
		{
			perror("shmget");
			exit(-1);
		}
	}
    else //first
    {
	    if ((shmaddr = (SHM *)shmat(shmid, NULL, 0)) == (SHM *)-1)//添加映射
    	{
	    	perror("shmat");
		    exit(-1);
    	}

        shmaddr->pid = getpid();
        pause();
        peerpid = shmaddr->pid;
    }

    while (1)
    {
        fgets(shmaddr->buf, N, stdin);
        kill(peerpid, SIGUSR1);
        if (strncmp(shmaddr->buf, "quit", 4) == 0)
            break;
        pause();
    }

	if (shmdt(shmaddr) == -1) //解除映射
	{
		perror("shmdt");
        exit(-1);
	}

	if (shmctl(shmid, IPC_RMID, NULL) == -1)//释放共享内存
	{
		perror("RM");
		exit(-1);
	}

    exit(0);
}


//reader.c
#include <stdio.h>
#include <unistd.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>

#define N 1024

typedef struct
{
    pid_t pid;
    char buf[N];
}SHM;

void handler(int signo)
{
}

int main()
{
	key_t key;
	int shmid;
	SHM *shmaddr;
	pid_t peerpid;

    signal(SIGUSR1, handler);

	if ((key = ftok(".", 'a')) == -1)
	{
		perror("ftok");
		exit(-1);
	}

	if ((shmid = shmget(key, sizeof(SHM), 0666 | IPC_CREAT | IPC_EXCL)) == -1)
	{
		if (errno == EEXIST)
		{
			shmid = shmget(key, sizeof(SHM), 0666);
	
            if ((shmaddr = (SHM *)shmat(shmid, NULL, 0)) == (SHM *)-1)
        	{
	        	perror("shmat");
		        exit(-1);
        	}
            peerpid = shmaddr->pid;
            shmaddr->pid = getpid();
            kill(peerpid, SIGUSR1);
		}
		else
		{
			perror("shmget");
			exit(-1);
		}
	}
    else //first
    {
	    if ((shmaddr = (SHM *)shmat(shmid, NULL, 0)) == (SHM *)-1)
    	{
	    	perror("shmat");
		    exit(-1);
    	}

        shmaddr->pid = getpid();
        pause();
        peerpid = shmaddr->pid;
    }

    while (1)
    {
        pause();
        printf("%s", shmaddr->buf);
        if (strncmp(shmaddr->buf, "quit", 4) == 0)
            break;
        kill(peerpid, SIGUSR1);
    }

	if (shmdt(shmaddr) == -1)
	{
		perror("shmdt");
        exit(-1);
	}

    exit(0);
}





你可能感兴趣的:(linux,struct,kill,cmd,null,Signal)