您的位置:首页 > 运维架构 > Linux

Linux进程通信之共享内存

2015-06-26 16:59 549 查看
Linux进程通信之共享内存
共享内存顾名思义就是几个进程共享一块内存区域,由于共享内存不需要数据在几个进程间来回复制,因此,共享内存是进程间通信方式中最快最为高效的。

所谓的共享内存就是内存分配一段物理内存,然后不同的进程可以将这一段内存地址连接到它们自己的地址空间中,然后进行访问,我们也可称这个过程为映射。搞清楚了共享内存的基本概念,下面我们就来看看相关的函数:

(1)创建共享内存

int shmget(key_t key , size_t size , int shmflg);

key: 键值,通过这个键值来创建我们的标识符,有关这个键值的详细信息在前面我们的信号量中我们有详细介绍,在此就不多说了。

size: 指定创建共享内存的大小,以字节为单位。

shmflg: 权限标志,指定该内存区域的可读可写性。

这个函数将创建一块内存区域,并且返回其标识符。

(2)链接到内存地址

void *shmat(int shmid , const void *addr , int flag);

shmid:也就是上面一个函数返回的标识符。

addr:指定共享内存链接到当前进程地址空间的地址,建议指定为空,这时会由系统来分配合适的位置。

flag: 建议为0。

这个函数就是完成我们共享内存地址到我们进程自己地址空间的连接,其返回值就是返回这个连接后的地址,是一个指针,通过这个指针我们可以访问共享内存区域。

(3)分离进程和共享内存段

void *shmdt(void *addr);

addr:就是上一个函数返回的指针。

这个函数只是把当前进程与这个内存区域分离,但是并不是删除这个内存区域,删除这块内存区域需要另外的操作。

以上就是Linux中共享内存编程比较常用的相关函数,下面我们就来用程序实例来了解下这些函数的用法:

实例一 共享内存方式实现父子进程通信:

#include <sys/ipc.h>

#include <sys/shm.h>

#include <sys/types.h>

#include <string.h>

#include <stdio.h>

#include <unistd.h>

void main(int argc , char **argv)

{

int smid;

char *smemory;

if(argc!=2)

{

printf("wrong para!!!\n");

exit(0);

}

smid = shmget(IPC_PRIVATE , 1024 , IPC_CREAT|0666);

smemory = shmat(smid , 0 ,0);

if(fork())

{

smemory = shmat(smid ,0 ,0);

memset(smemory , '\0' , 1024);

strncpy(smemory , argv[1],30);

exit(1);

}

else

{

smemory = shmat(smid ,0 ,0);

printf("father_son_pro ? %s\n" ,smemory);

exit(1);

}

shmdt(smemory);

}

这个程序实现了利用共享内存方式在父子进程之间进行通信,父进程通过命令行向共享区域写入信息,然后子进程从这个共享区域读取信息并打印。

实例二:共享内存在任意两个进程间实现通信

进程A代码:

#include <sys/ipc.h>

#include <sys/shm.h>

#include <sys/types.h>

#include <string.h>

#include <stdio.h>

#include <unistd.h>

void main(int argc , char **argv)

{

int smid;

key_t key;

char *smemory;

if(argc!=2)

{

printf("have the wrong para\n");

exit(1);

}

key = ftok("/home" , 1); //类似我们的信号量方式获取键值

smid = shmget(key , 1024 , IPC_CREAT|0666);

smemory = shmat(smid , 0 , 0);

memset(smemory , '\0' , 1024);

strncpy(smemory , argv[1], 30);

shmdt(smemory);

}

进程B代码:

#include <sys/ipc.h>

#include <sys/shm.h>

#include <sys/types.h>

#include <string.h>

#include <stdio.h>

#include <unistd.h>

void main()

{

int smid;

key_t key;

char *smemory;

key = ftok("/home" , 1); //类似我们的信号量方式获取键值

smid = shmget(key , 1024 , IPC_CREAT|0666);

smemory = shmat(smid , 0 , 0);

printf("is ok ? %s\n" , smemory);

shmdt(smemory);

}

在这两个进程中,进程A通过命令行向共享内存区写入信息,然后进程B也去访问这个共享内存区,读取其中的信息并打印出来。

我们发现,采用共享内存的方式来实现进程间通信是非常简单的,编程代码量也只有几句话,但是我们看完上面的程序是不是会有疑问,要是有多个进程同时访问这个区域,不就乱套了,确实,这算是共享内存的弱点吧,共享内存并未提供同步机制,因此在第一个进程访问这快区域时,不能阻止其他进程来访问,为了保证各进程间利用共享内存的友好通信,我们一般需要添加其他同步机制,比方说我们前面提到的信号量。下面就来编写一个利用信号量来实现进程间共享内存通信的同步:

实例三:利用信号量实现多进程间共享内存通信的同步

进程A用于向共享内存写入数据,并且作为类似生产者,释放信号量。

#include <sys/ipc.h>

#include <sys/shm.h>

#include <sys/types.h>

#include <sys/sem.h>

#include <string.h>

#include <stdio.h>

#include <unistd.h>

void main()

{

key_t signal_key;

int signal_mid;

struct sembuf sops; //信号量操作结构体

key_t memory_key;

int memory_mid;

char *smemory; //共享内存相关变量

//创建一个包含一个信号量的信号量集

signal_key = ftok("/home" , 0);

signal_mid = semget(signal_key , 1 ,IPC_CREAT);

//设置信号量的初值为0

semctl(signal_mid , 0 , SETVAL , 0);

/***********************************

临界代码段

***********************************/

//创建一个共享内存

memory_key = ftok("/home" , 1);

memory_mid = shmget(memory_key ,1024 ,IPC_CREAT|0666);

smemory = (char*)shmat(memory_mid ,0 ,0);

memset(smemory , '\0 ', 1024);

strncpy(smemory , "this is pro_oneprocess", 50);

shmdt(smemory); //将创建的共享内存段与进程分离

sleep(10);

/********************

释放信号量

*********************/

sops.sem_num = 0;

sops.sem_op = 1;

sops.sem_flg = SEM_UNDO;

semop(signal_mid , &sops , 1);

}

进程B用于获取共享内存信息并打印,类似消费者,需要等待信号量。

#include <sys/ipc.h>

#include <sys/shm.h>

#include <sys/types.h>

#include <sys/sem.h>

#include <string.h>

#include <stdio.h>

#include <unistd.h>

void main()

{

key_t signal_key;

int signal_mid;

struct sembuf sops; //信号量操作结构体

key_t memory_key;

int memory_mid;

char *smemory;

//创建一个包含一个信号量的信号量集

signal_key = ftok("/home" , 0);

signal_mid = semget(signal_key , 1 ,IPC_CREAT);

//设置信号量的初值为0

semctl(signal_mid , 0 , SETVAL , 0);

//获取信号量,如果信号量已被其它进程使用,则等待

sops.sem_num = 0;

sops.sem_op = -1;

sops.sem_flg = SEM_UNDO;

semop(signal_mid , &sops , 1);

/***********************************

临界代码段

***********************************/

//创建一个共享内存

memory_key = ftok("/home" , 1);

memory_mid = shmget(memory_key ,1024 ,IPC_CREAT|0666);

smemory = (char*)shmat(memory_mid ,0 ,0);

printf("%s\n" , smemory);

shmdt(smemory); //将创建的共享内存段与进程分离

}

以上两个程序就是利用信号量的同步机制来实现进程间共享内存的同步,类似于我们的生产者与消费者,把这里的共享内存区域当做产品。

以上就是共享内存的一些基本知识,详细的知识我们可以通过相关的文档来进行查阅。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: