linux下共享内存

C programming in the UNIX environment的编程手册,一般都会为进程间用共享内存的方法通信提供两组方法:

1.      SYSTEM V定义的

int shmget(key_t key, int size, int shmflg);  //得到一个共享内存标识符或创建一个共享内存对象
void *shmat(int shmid, const void *shmaddr, int shmflg); //把共享内存区对象映射到调用进程的地址空间
int shmdt(const void *shmaddr); //断开共享内存连接
int shmctl(int shmid, int cmd, struct shmid_ds *buf); //完成对共享内存的控制可以修改共享内存信息,也可以删除这片贡献内存。

例子代码如下:

#include <stdio.h> 
#include <unistd.h> 
#include <string.h> 
#include <sys/ipc.h> 
#include <sys/shm.h> 
#include <error.h> 
#define SIZE 1024 
int main() 
 { 
	  int shmid ; 
	    char *shmaddr ; 
		  struct shmid_ds buf ; 
		    int flag = 0 ; 
			  int pid ; 
			    shmid = shmget(IPC_PRIVATE, SIZE, IPC_CREAT|0600 ) ; 
				  if ( shmid < 0 ) 
				    { 
						  perror("get shm ipc_id error") ; 
						    return -1 ; 
				    } 
				    pid = fork() ; 
					  if ( pid == 0 ) 
					    { 
							  shmaddr = (char *)shmat( shmid, NULL, 0 ) ; 
							    if ( (int)shmaddr == -1 ) 
								  { 
									    perror("shmat addr error") ; 
										  return -1 ; 
								  } 
								  strcpy( shmaddr, "Hi, I am child process!\n") ; 
								    shmdt( shmaddr ) ; 
									  return 0; 
					    } else if ( pid > 0) { 
							  sleep(3 ) ; 
							    flag = shmctl( shmid, IPC_STAT, &buf) ; 
								  if ( flag == -1 ) 
								    { 
										  perror("shmctl shm error") ; 
										    return -1 ; 
								    } 
								    printf("shm_segsz =%d bytes\n", buf.shm_segsz ) ; 
									  printf("parent pid=%d, shm_cpid = %d \n", getpid(), buf.shm_cpid ) ; 
									    printf("chlid pid=%d, shm_lpid = %d \n",pid , buf.shm_lpid ) ; 
										  shmaddr = (char *) shmat(shmid, NULL, 0 ) ; 
										    if ( (int)shmaddr == -1 ) 
											  { 
												    perror("shmat addr error") ; 
													  return -1 ; 
											  } 
											  printf("%s", shmaddr) ; 
											    shmdt( shmaddr ) ; 
												  shmctl(shmid, IPC_RMID, NULL) ; 
					    }else{ 
							  perror("fork error") ; 
							    shmctl(shmid, IPC_RMID, NULL) ; 
						  } 
						  return 0 ; 
}


        编译 gcc shm.c –o shm。

  执行 ./shm,执行结果如下:

  shm_segsz =1024 bytes

  shm_cpid = 9503

  shm_lpid = 9504

       Hi, I am child process!

2.      POSIX定义的:

int shm_open(const char *name, int oflag, mode_t mode);  //最主要的操作也是默认的操作就是在/dev/shm/下面,建立一个文件,文件名字是用户自己输入的。

参数:name 共享内存区的名字(不能为空), cflag 标志位 mode 权限位    返回值:成功返回0,出错返回-1

oflag参数必须含有O_RDONLY和O_RDWR标志,还可以指定如下标志:O_CREAT,O_EXCL或O_TRUNC.

mode参数指定权限位,它指定O_CREAT标志的前提下使用。 shm_open的返回值是一个整数描述字,它随后用作mmap的第五个参数。
int shm_unlink(const char *name);  //删除一个共享内存区,返回值,0成功,-1失败。

int ftruncate(int fd, off_t length);  //分配大小

void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset); //将一个文件或者其它对象映射进内存

返回值:如果mmap成功则返回映射首地址,如果出错则返回常数MAP_FAILED。
参数:
addr    指向映射存储区的起始地址;
len        映射的字节
prot    对映射存储区的保护要求
flag    标志位
filedes    要被映射文件的描述符
off    要映射字节在文件中的起始偏移量
参数解释如下:整体相当于磁盘文件的对应长度搬移到内存中。如果addr参数为NULL,内核会自己在进程地址空间中选择合适的地址建立映射。
如果addr不是NULL,则给内核一个提示,应该从什么地址开始映射,内核会选择addr之上的某个合适的地址开始映射。建立映射后,真正的
映射首地址通过返回值可以得到。off参数是从文件的什么位置开始映射,必须是页大小的
整数倍(在32位体系统结构上通常是4K)。
prot参数有四种取值:
 PROT_EXEC表示映射的这一段可执行,例如映射共享库
 PROT_READ表示映射的这一段可读
 PROT_WRITE表示映射的这一段可写
 PROT_NONE表示映射的这一段不可访问
 flag参数有很多种取值,这里只讲两种,
 MAP_SHARED多个进程对同一个文件的映射是共享的,一个进程对映射的内存做了修改,另一个进程也会看到这种变化。
 MAP_PRIVATE多个进程对同一个文件的映射不是共享的,一个进程对映射的内存做了修改,另一个进程并不会看到这种变化,也不会真的写到文件中去。

int fstat(int fd, struct stat *buf)  //当打开一个已经从在的共享内存时,我们调用fstat 来获取有关该对象的信息

int munmap(void *addr,size_t len)  // 要删除一个已经建立的映射关系

int msync (void *addr,size_t len,int flags) //实现同步或者异步

由于POSIX标准比较通用,一般建议使用该标准定义的方法集。但在编译的时候可能会出现“undefined reference to `shm_open'”的错误,加上--lrt就可以编过。

客户服务段两进程通信实例:

服务端:
#include <stdio.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
#include <semaphore.h>
#include <string.h>
int main(int argc,char **argv)
{
    int shm_id;
    char *ptr;
    sem_t *sem;
    if (argc!=2)
    {
        printf("usage:shm_open<pathname>\n");
        return -1;
    }
    shm_id=shm_open(argv[1],O_RDWR|O_CREAT,0644);/*第一步:创建共享内存区*/
    if (shm_id==-1)
    {
        printf( "open shared memory error.errno=%d,desc=%s.\n", errno, strerror(errno));
        return -1;
    }
    ftruncate(shm_id,100);/*第二步:调整共享内存区大小,shmid问shm_open的返回值*/
    sem=sem_open(argv[1],O_CREAT,0644,0);/*创建信号量*/
    if (sem==SEM_FAILED)
    {
        printf( "open semaphore error.errno=%d,desc=%s.\n", errno, strerror(errno));
        return -1;
    }
    ptr=mmap(NULL,100,PROT_READ|PROT_WRITE,MAP_SHARED,shm_id,0);/*第三步:连接共享内存区*/
    strcpy(ptr,"\0");
    sem_wait(sem);/*第四步:申请信号量*/
    printf("server : %s\n",ptr);/*输入共享内存区内容*/
    strcpy(ptr,"\0");/*清空共享内存区*/
    sem_unlink(argv[1]);/*第五步:删除信号量*/
    shm_unlink(argv[1]);/*第六步:删除共享内存区*/
    return 0;
}

客户端:
#include <stdio.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
#include <semaphore.h>
#include <string.h>
#include <errno.h>
int main(int argc,char **argv)
{
    int shm_id;
    char *ptr;
    sem_t *sem;

    if (argc!=2)
    {
        printf("usage:shm_open <pathname>\n");
        return -1;
    }
    shm_id=shm_open(argv[1],O_RDWR,0);/*第一步:打开共享内存区*/
    if (shm_id==-1)
    {
        printf( "open shared memory error.errno=%d,desc=%s.\n", errno, strerror(errno));
        return -1;
    }
    else
    {
        printf( "open shared memory ok.\n");
    }
    sem=sem_open(argv[1],0);/*打开信号量*/
    if (sem==SEM_FAILED)
    {
        printf( "open semaphore error.errno=%d,desc=%s.\n", errno, strerror(errno));
        return -1;
    }
    else
    {
        printf( "open semaphore ok.\n");
    }
    ptr=mmap(NULL,100,PROT_READ|PROT_WRITE,MAP_SHARED,shm_id,0);/*连接共享内存区*/
    fgets(ptr,10,stdin);/*从键盘读入数据到共享内存区*/
    printf("user : %s",ptr);
    sem_post(sem);/*释放信号量*/
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

山西茄子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值