精华内容
下载资源
问答
  • Linux下共享内存编程(共享存储空间)

    万次阅读 多人点赞 2018-07-29 23:44:08
    最简单的共享内存的使用流程 ①ftok函数生成键值 ②shmget函数创建共享内存空间 ③shmat函数获取第一个可用共享内存空间的地址 ④shmdt函数进行分离(对共享存储段操作结束时的步骤,并不是从系统中删除共享内存...

    共享存储允许两个或多个进程共享一个给定的存储区,是进程间通信最快的一种方式。

    不要同时对共享存储空间进行写操作,通常,信号量用于同步共享存储访问。

    最简单的共享内存的使用流程

    ①ftok函数生成键值

    ②shmget函数创建共享内存空间

    ③shmat函数获取第一个可用共享内存空间的地址

    ④shmdt函数进行分离(对共享存储段操作结束时的步骤,并不是从系统中删除共享内存和结构)

    ⑤shmctl函数进行删除共享存储空间

    1.ftok函数生成键值

    每一个共享存储段都有一个对应的键值(key)相关联(消息队列、信号量也同样需要)。

    所需头文件:#include<sys/ipc.h>

    函数原型 :key_t ftok(const char *path ,int id);

    path为一个已存在的路径名

    id为0~255之间的一个数值,代表项目ID,自己取

    返回值:成功返回键值(相当于32位的int)。出错返回-1

    例如:key_t key = ftok( “/tmp”, 66);

    2.shmget函数创建共享存储空间并返回一个共享存储标识符

    所需头文件:#include<sys/shm.h>

    函数原型: int shmget(key_t key, size_t size,int flag);

    key为ftok生成的键值

    size为共享内存的长度,以字节为单位

    flag为所需要的操作和权限,可以用来创建一个共享存储空间并返回一个标识符或者获得一个共享标识符。

    flag的值为IPC_CREAT:如果不存在key值的共享存储空间,且权限不为0,则创建共享存储空间,并返回一个共享存储标识符。如果存在,则直接返回共享存储标识符。

    flag的值为 IPC_CREAT | IPC_EXCL:如果不存在key值的共享存储空间,且权限不为0,则创建共享存储空间,并返回一个共享存储标识符。如果存在,则产生错误。

    返回值:成功返回共享存储ID;出错返回-1

    例如:int id = shmget(key,4096,IPC_CREAT|IPC_EXCL|0666);创建一个大小为4096个字节的权限为0666(所有用户可读可写,具体查询linux权限相关内容)的共享存储空间,并返回一个整形共享存储标识符,如果key值已经存在有共享存储空间了,则出错返回-1。

         int id = shmget(key,4096,IPC_CREAT|0666);创建一个大小为4096个字节的权限为0666(所有用户可读可写,具体查询linux权限相关内容)的共享存储空间,并返回一个共享存储标识符,如果key值已经存在有共享存储空间了,则直接返回一个共享存储标识符。

    3.shmat函数获取第一个可用共享内存空间的地址

    所需头文件:#include<sys/shm.h>

    函数原型: void *shmat(int shmid, const void *addr, int flag);

    shmid为shmget生成的共享存储标识符

    addr指定共享内存出现在进程内存地址的什么位置,直接指定为NULL让内核自己决定一个合适的地址位置

    flag为对数据的操作,如果指定为SHM_RDONLY则以只读方式连接此段,其他值为读写方式连接此段。

    翻阅linux下shm.c文件得到#define SHM_RDONLY      010000  /* read-only access */

    返回值:成功返回指向共享存储段的指针;错误返回-1(打印出指针的值为全F)

    例如:char *addr  = shmat(id, NULL, 0);就会返回第一个可用的共享内存地址的指针的值给addr 

    4.shmdt函数进行分离

    当不需要对此共享内存进行操作时候,调用shmdt函数进行分离,不是删除此共享存储空间哟。

    所需头文件:#include<sys/shm.h>

    函数原型: int shmdt(const void *addr);

    addr为shmat函数返回的地址指针

    返回值:成功返回0;错误返回-1

    例如:int ret = shmdt(addr);

    5.shmctl函数对共享内存进行控制

    简单的操作就是删除共享存储空间了,也可以获取和改变共享内存的状态

    所需头文件:#include<sys/shm.h>

    函数原型:int shmctl(int shmid, int cmd, struct shmid_ds *buf);

    shmid就是shmget函数返回的共享存储标识符

    cmd有三个,常用删除共享内存的为IPC_RMID;IPC_STAT:得到共享内存的状态,把共享内存的shmid_ds结构复制到buf中;IPC_SET:改变共享内存的状态,把buf所指的shmid_ds结构中的uid、gid、mode复制到共享内存的shmid_ds结构内。(内核为每个共享存储段维护着一个结构,结构名为shmid_ds,这里就不讲啦,里面存放着共享内存的大小,pid,存放时间等一些参数)

    buf就是结构体shmid_ds

    返回值:成功返回0;错误返回-1

    例如:int ret = shmctl(id, IPC_RMID,NULL);删除id号的共享存储空间

     

    ps:在Linux下,比如你申请24字节大小的共享存储空间,系统还是会默认给你分配一页的大小,但你还是只能使用这一页上24字节的空间。使用getconf PAGE_SIZE 命令就能显示出一页的大小

    使用ipcs -m可以查看当前系统所有的共享内存空间信息

    如果你的程序创建了一个共享内存段,但没有销毁,可以使用命令ipcrm -m shmid命令删除共享内存段,不然程序再运行有可能出错。

    下面用一个代码例子来使用共享内存

    我创建了一个结构体,想让结构体存入共享内存。写了两个程序,service和client,代码基本相同,不同就是service程序的开始创建共享内存。这两个程序是一个死循环,让你选择是存数据还是读数据还是销毁共享内存。代码写的不是很精致,主要是为了练共享内存,见谅哈。

    command.c文件,构造想存入的结构体,和共享内存的操作函数

    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    #include<sys/types.h>
    #include<sys/shm.h>
    #include "Command.h"
    int sharememory(int ipc_size,int flag)
    {
    	int id;
    	key_t key=ftok("/tmp",66);
    	if(key < 0)
    	{
    		printf("get key error\n");
    		return -1;
    	}
    	id = shmget(key,ipc_size,flag);
    	if(id < 0)
    	{
    		printf("get id error\n");
    		return -1;
    	}
    	return id;
    }
    
    int create_ipc(int ipc_size)
    {
    	return sharememory(ipc_size,IPC_CREAT|IPC_EXCL|0666);
    }
    int get_ipc(int ipc_size)
    {
    	return sharememory(ipc_size,IPC_CREAT|0666);
    }
    int destroy_sharememory(int id)
    {
    	return shmctl(id,IPC_RMID,NULL);
    }

    command.h文件。好让service和client调用嘛,方便。

    #define NAME_LEN 20
    typedef struct {
    	char name[NAME_LEN];
    	int age;
    }ckx;
    int sharememory(int ipc_size,int flag);
    int create_ipc(int ipc_size);
    int get_ipc(int ipc_size);

    service.c文件。创建共享内存空间啦,读写等

    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    #include<sys/shm.h>
    #include<sys/types.h>
    #include<stdlib.h>
    #include "Command.h"
    
    int main()
    {
    	int id=create_ipc(sizeof(ckx));
    	int i=0;
    	ckx *p;
    	if(id < 0)
    	{
    		printf("create sharememory error\n");
    		return 0;
    	}
    	id = 0;
    	while(1)
    	{
    		printf("\n\n1.input data to sharememory\n2.get sharememory data\n\
    3.destroy sharememory\ninput select:");
    		scanf("%d",&i);
    		if(i > 3 |i< 1)
    		{
    			printf("input error\n");
    			continue;
    		}
    		
    		id = get_ipc(sizeof(ckx));
    		if(id < 0)
    		{
    			printf("get sharememory error\n");
    			break;
    		}
    		p = (ckx *)shmat(id,NULL,0);
    		if(p < 0)
    		{
    			printf("get sharememory addr error\n");
    			p = NULL;
    			break;
    		}
    		
    		if(i == 1)
    		{
    			char name[NAME_LEN];
    			int age=0;
    			
    			printf("input name:");
    			fflush(stdin);
    			getchar();
    			gets(name);
    			printf("input age:");
    			scanf("%d",&age);
    			
    			strcpy(p->name,name);
    			p->age = age;
    			printf("write success\n");
    
    			if(shmdt(p) == -1)
    			{
    				printf("shmdt error\n");
    			}
    			id = 0;
    		}
    		if(i ==  2)
    		{
    			printf("name:%s \t age:%d\n",p->name,p->age);
    			if(shmdt(p) == -1)
    			{
    				printf("shmdt error\n");
    				break;
    			}
    			id = 0;
    		}
    		if(i == 3)
    		{
    			if(shmdt(p) == -1)
    			{
    				printf("shmdt error\n");
    				break;
    			}
    			break;
    		}
    	}
    	if(id !=0)
    	{
    		if(destroy_sharememory(id)<0)
    		{
    			printf("destroy error\n");
    		}
    	}
    }
    

    client.c基本上就和service.c代码差不多啦,只是想体现共享内存嘛,service读写和client读写,观察现象,体现共享内存

    #include<stdio.h>
    #include<sys/shm.h>
    #include<stdlib.h>
    #include<string.h>
    #include<sys/types.h>
    #include<stdlib.h>
    #include "Command.h"
    
    int main()
    {
    	int i=0;
    	ckx *p;
    	int id = 0;
    	while(1)
    	{
    		printf("\n\n1.input data to sharememory\n2.get sharememory data\n\
    3.destroy sharememory\ninput select:");
    		scanf("%d",&i);
    		if(i > 3 |i< 1)
    		{
    			printf("input error\n");
    			continue;
    		}
    		
    		id = get_ipc(sizeof(ckx));
    		if(id < 0)
    		{
    			printf("get sharememory error\n");
    			break;
    		}
    		p = (ckx *)shmat(id,NULL,0);
    		if(p < 0)
    		{
    			printf("get sharememory addr error\n");
    			p = NULL;
    			break;
    		}
    		
    		if(i == 1)
    		{
    			char name[NAME_LEN];
    			int age=0;
    			fflush(stdin);
    			getchar();
    			printf("input name:");
    			gets(name);
    			printf("input age:");
    			scanf("%d",&age);
    			
    			strcpy(p->name,name);
    			p->age = age;
    			printf("write success\n");
    
    			if(shmdt(p) == -1)
    			{
    				printf("shmdt error\n");
    			}
    			id = 0;
    		}
    		if(i ==  2)
    		{
    			printf("name:%s \t age:%d\n",p->name,p->age);
    			if(shmdt(p) == -1)
    			{
    				printf("shmdt error\n");
    				break;
    			}
    			id = 0;
    		}
    		if(i == 3)
    		{
    			if(shmdt(p) == -1)
    			{
    				printf("shmdt error\n");
    				break;
    			}
    			break;
    		}
    	}
    	if(id !=0)
    	{
    		if(destroy_sharememory(id)<0)
    		{
    			printf("destroy error\n");
    		}
    	}
    	
    	
    }
    

     

    展开全文
  • Linux共享内存编程实例

    万次阅读 2014-08-24 00:32:09
    转子: [cpp] view plaincopy ... 在GNU/Linux中所有的进程都有唯一的虚拟地址空间,而共享内存应用编程接口API允许一个进程使   用公共内存区段。但是对内存的共享访问其复杂度也相应增加

    转自:http://blog.csdn.net/pcliuguangtao/article/details/6526119/

    共享内存是LUNIX 系统中最底层的通信机制,也是最快速的通信机制。共享内存通过两个或多个进程共享同一块内存区域来实现进程间的通信。通常是由一个进程创建一块共享内存区域,然后多个进程可以对其进行访问,一个进程将要传出的数据存放到共享内存中,另一个或多个进程则直接从共享内存中读取数据。因此这种通信方式是最高效的进程间通信方式。但实际的问题在于,当两个或多个进程使用共享内存进行通信时,同步问题的解决显得尤为重要,否则就会造成因不同进程同时读写一块共享内存中的数据而发生混乱。在通常的情况下,通过使用信号量来实现进程的同步。

    1. /*共享内存允许两个或多个进程进程共享同一块内存(这块内存会映射到各个进程自己独立的地址空间) 
    2.   从而使得这些进程可以相互通信。 
    3.   在GNU/Linux中所有的进程都有唯一的虚拟地址空间,而共享内存应用编程接口API允许一个进程使 
    4.   用公共内存区段。但是对内存的共享访问其复杂度也相应增加。共享内存的优点是简易性。 
    5.   使用消息队列时,一个进程要向队列中写入消息,这要引起从用户地址空间向内核地址空间的一次复制, 
    6.   同样一个进程进行消息读取时也要进行一次复制。共享内存的优点是完全省去了这些操作。 
    7.   共享内存会映射到进程的虚拟地址空间,进程对其可以直接访问,避免了数据的复制过程。 
    8.   因此,共享内存是GNU/Linux现在可用的最快速的IPC机制。 
    9.   进程退出时会自动和已经挂接的共享内存区段分离,但是仍建议当进程不再使用共享区段时 
    10.   调用shmdt来卸载区段。 
    11.   注意,当一个进程分支出父进程和子进程时,父进程先前创建的所有共享内存区段都会被子进程继承。 
    12.   如果区段已经做了删除标记(在前面以IPC——RMID指令调用shmctl),而当前挂接数已经变为0, 
    13.   这个区段就会被移除。 
    14.  */  
    15. /* 
    16.   shmget(  )  创建一个新的共享内存区段 
    17.               取得一个共享内存区段的描述符 
    18.   shmctl(  )  取得一个共享内存区段的信息 
    19.               为一个共享内存区段设置特定的信息 
    20.               移除一个共享内存区段 
    21.   shmat(  )   挂接一个共享内存区段 
    22.   shmdt(  )   于一个共享内存区段的分离 
    23.  */  
    24. //创建一个共享内存区段,并显示其相关信息,然后删除该内存共享区  
    25. #include <stdio.h>  
    26. #include <unistd.h>  //getpagesize(  )  
    27. #include <sys/ipc.h>  
    28. #include <sys/shm.h>  
    29. #define MY_SHM_ID 67483  
    30. int main(  )  
    31.     {  
    32.         //获得系统中页面的大小  
    33.         printf( "page size=%d/n",getpagesize(  ) );  
    34.         //创建一个共享内存区段  
    35.         int shmid,ret;  
    36.         shmid=shmget( MY_SHM_ID,4096,0666|IPC_CREAT );  
    37.         //创建了一个4KB大小共享内存区段。指定的大小必须是当前系统架构  
    38.         //中页面大小的整数倍  
    39.         if( shmid>0 )  
    40.             printf( "Create a shared memory segment %d/n",shmid );  
    41.         //获得一个内存区段的信息  
    42.         struct shmid_ds shmds;  
    43.         //shmid=shmget( MY_SHM_ID,0,0 );//示例怎样获得一个共享内存的标识符  
    44.         ret=shmctl( shmid,IPC_STAT,&shmds );  
    45.         if( ret==0 )  
    46.             {  
    47.                 printf( "Size of memory segment is %d/n",shmds.shm_segsz );  
    48.                 printf( "Numbre of attaches %d/n",( int )shmds.shm_nattch );  
    49.             }  
    50.         else  
    51.             {  
    52.                 printf( "shmctl(  ) call failed/n" );  
    53.             }  
    54.         //删除该共享内存区  
    55.         ret=shmctl( shmid,IPC_RMID,0 );  
    56.         if( ret==0 )  
    57.             printf( "Shared memory removed /n" );  
    58.         else  
    59.             printf( "Shared memory remove failed /n" );  
    60.         return 0;  
    61.     }  
    62.   
    63. //共享内存区段的挂载,脱离和使用  
    64. //理解共享内存区段就是一块大内存  
    65. #include <stdio.h>  
    66. #include <sys/shm.h>  
    67. #include <sys/ipc.h>  
    68. #include <errno.h>  
    69. #define MY_SHM_ID 67483  
    70. int main(  )  
    71.     {  
    72.         //共享内存区段的挂载和脱离  
    73.         int shmid,ret;  
    74.         void* mem;  
    75.         shmid=shmget( MY_SHM_ID,0,0 );  
    76.         if( shmid>=0 )  
    77.             {  
    78.                 mem=shmat( shmid,( const void* )0,0 );  
    79.                 //shmat()返回进程地址空间中指向区段的指针  
    80.                 if( ( int )mem!=-1 )  
    81.                     {  
    82.                         printf( "Shared memory was attached in our address space at %p/n",mem );  
    83.                         //向共享区段内存写入数据  
    84.                         strcpy( ( char* )mem,"This is a test string./n" );  
    85.                         printf( "%s/n",(char*)mem );  
    86.                         //脱离共享内存区段  
    87.                         ret=shmdt( mem );  
    88.                         if( ret==0 )  
    89.                             printf( "Successfully detached memory /n" );  
    90.                         else  
    91.                             printf( "Memory detached failed %d/n",errno );  
    92.                     }  
    93.                 else  
    94.                     printf( "shmat(  ) failed/n" );  
    95.                   
    96.             }  
    97.         else  
    98.             printf( "shared memory segment not found/n" );  
    99.         return 0;  
    100.     }  
    101. /*内存共享区段与旗语和消息队列不同,一个区段可以被锁定。 
    102.   被锁定的区段不允许被交换出内存。这样做的优势在于,与其 
    103.   把内存区段交换到文件系统,在某个应用程序调用时再交换回内存, 
    104.   不如让它一直处于内存中,且对多个应用程序可见。从提升性能的角度 
    105.   来看,很重要的。 
    106.  */  
    107. int shmid;  
    108. //...  
    109. shmid=shmget( MY_SHM_ID,0,0 );  
    110. ret=shmctl( shmid,SHM_LOCK,0 );  
    111. if( ret==0 )  
    112.     printf( "Locked!/n" );  
    113.   
    114. /*使用旗语协调共享内存的例子 
    115.   使用和编译命令 
    116.   gcc -Wall test.c -o test 
    117.   ./test create 
    118.   ./test use a & 
    119.   ./test use b & 
    120.   ./test read & 
    121.   ./test remove  
    122.  */  
    123. #include <stdio.h>  
    124. #include <sys/shm.h>  
    125. #include <sys/ipc.h>  
    126. #include <sys/sem.h>  
    127. #include <string.h>  
    128. #include <stdlib.h>  
    129. #include <unistd.h>  
    130. #define MY_SHM_ID 34325  
    131. #define MY_SEM_ID 23234  
    132. #define MAX_STRING 200  
    133. typedef struct  
    134. {  
    135.     int semID;  
    136.     int counter;  
    137.     char string[ MAX_STRING+1 ];  
    138. }MY_BLOCK_T;  
    139. int main(int argc,char** argv)  
    140.     {  
    141.         int shmid,ret,i;  
    142.         MY_BLOCK_T* block;  
    143.         struct sembuf sb;  
    144.         char user;  
    145.         //make sure there is a command  
    146.         if( argc>=2 )  
    147.             {  
    148.                 //create the shared memory segment and init it  
    149.                 //with the semaphore  
    150.               if( !strncmp(argv[ 1 ],"create",6) )  
    151.                     {  
    152.                         //create the shared memory segment and semaphore  
    153.                         printf( "Creating the shared memory/n" );  
    154.                         shmid=shmget( MY_SHM_ID,sizeof( MY_BLOCK_T ),( IPC_CREAT|0666 ) );  
    155.                         block=( MY_BLOCK_T* )shmat( shmid,( const void* )0,0 );  
    156.                         block->counter=0;  
    157.                         //create the semaphore and init  
    158.                         block->semID=semget(MY_SEM_ID,1,( IPC_CREAT|0666 ));  
    159.                         sb.sem_num=0;  
    160.                         sb.sem_op=1;  
    161.                         sb.sem_flg=0;  
    162.                         semop( block->semID,&sb,1 );  
    163.                         //now detach the segment  
    164.                         shmdt( ( void* )block );  
    165.                         printf( "Create the shared memory and semaphore successuflly/n" );  
    166.                           
    167.                     }  
    168.                 else if( !strncmp(argv[ 1 ],"use",3) )  
    169.                     {  
    170.                         /*use the segment*/  
    171.                         //must specify  also a letter to write to the buffer  
    172.                         if( argc<3 ) exit( -1 );  
    173.                         user=( char )argv[ 2 ][ 0 ];  
    174.                         //grab the segment  
    175.                         shmid=shmget( MY_SHM_ID,0,0 );  
    176.                         block=( MY_BLOCK_T* )shmat( shmid,( const void* )0,0 );  
    177.                           
    178.                         /*##########重点就是使用旗语对共享区的访问###########*/  
    179.                         for( i=0;i<100;++i )  
    180.                         {  
    181.                             sleep( 1 ); //设置成1s就会看到 a/b交替出现,为0则a和b连续出现  
    182.                         //grab the semaphore  
    183.                         sb.sem_num=0;  
    184.                         sb.sem_op=-1;  
    185.                         sb.sem_flg=0;  
    186.                         if( semop( block->semID,&sb,1 )!=-1 )  
    187.                             {  
    188.                                 //write the letter to the segment buffer  
    189.                                 //this is our CRITICAL SECTION  
    190.                                 block->string[ block->counter++ ]=user;  
    191.                                   
    192.                                 sb.sem_num=0;  
    193.                                 sb.sem_op=1;  
    194.                                 sb.sem_flg=0;  
    195.                                 if( semop( block->semID,&sb,1 )==-1 )  
    196.                                     printf( "Failed to release the semaphore/n" );  
    197.                                   
    198.                             }  
    199.                         else  
    200.                             printf( "Failed to acquire the semaphore/n" );  
    201.                         }  
    202.                           
    203.                        //do some clear work  
    204.                         ret=shmdt(( void*)block);  
    205.                           
    206.                     }  
    207.                 else if( !strncmp(argv[ 1 ],"read",4) )  
    208.                     {  
    209.                         //here we will read the buffer in the shared segment  
    210.                         shmid=shmget( MY_SHM_ID,0,0 );  
    211.                         if( shmid!=-1 )  
    212.                             {  
    213.                                 block=( MY_BLOCK_T* )shmat( shmid,( const void* )0,0 );  
    214.                                 block->string[ block->counter+1 ]=0;  
    215.                                 printf( "%s/n",block->string );  
    216.                                 printf( "Length=%d/n",block->counter );  
    217.                                 ret=shmdt( ( void*)block );  
    218.                              }  
    219.                         else  
    220.                             printf( "Unable to read segment/n" );  
    221.                   
    222.                     }  
    223.                 else if( !strncmp(argv[ 1 ],"remove",6) )  
    224.                     {  
    225.                         shmid=shmget( MY_SHM_ID,0,0 );  
    226.                         if( shmid>=0 )  
    227.                             {  
    228.                                 block=( MY_BLOCK_T* )shmat( shmid,( const void* )0,0 );  
    229.                                 //remove the semaphore  
    230.                                 ret=semctl( block->semID,0,IPC_RMID );  
    231.                                 if( ret==0 )  
    232.                                     printf( "Successfully remove the semaphore /n" );  
    233.                                 //remove the shared segment  
    234.                                 ret=shmctl( shmid,IPC_RMID,0 );  
    235.                                 if( ret==0 )  
    236.                                     printf( "Successfully remove the segment /n" );  
    237.                             }  
    238.                     }  
    239.                 else  
    240.                     printf( "Unkonw command/n" );  
    241.             }  
    242.         return 0;  
    243.           
    244.     }  


    ++++++++++++++++++++++++++++++++++++++++++

    以下两个程序是一个进程间通信的例子。这两个程序分别在不同的进程中运行,使用了共享内存进行通信。b从键盘读入数据,存放在共享内存中。a则从共享内存中读取数据,显示到屏幕上。由于没有使两个进程同步,显示的内容将是杂乱无章的.实例b程序负责向共享内存中写入数据,a程序负责从内存中读出共享的数据,它们之间并没有添加同步操作。

    b.c

    #include <sys/types.h>   
    #include <sys/ipc.h>   
    #include <sys/shm.h>   
    #include <stdio.h>   
      
    #define BUF_SIZE 1024   
    #define MYKEY 25   
    int main()  
    {  
        int shmid;  
        char *shmptr;  
      
        if((shmid = shmget(MYKEY,BUF_SIZE,IPC_CREAT)) ==-1)  
        {  
        printf("shmget error \n");  
        exit(1);  
        }  
      
        if((shmptr =shmat(shmid,0,0))==(void *)-1)  
        {  
        printf("shmat error!\n");  
        exit(1);  
        }  
      
        while(1)  
        {  
        printf("input:");  
        scanf("%s",shmptr);  
        }  
      
        exit(0);  
    } 

    =======================================

    a.c
    #include <stdio.h>   
    #include <sys/types.h>   
    #include <sys/ipc.h>   
    #include <sys/shm.h>   
      
    #define BUF_SIZE 1024   
    #define MYKEY 25   
    int  main()  
    {  
        int shmid;  
        char * shmptr;  
      
        if((shmid = shmget(MYKEY,BUF_SIZE,IPC_CREAT)) ==-1)  
        {  
        printf("shmget error!\n");  
        exit(1);  
        }  
      
        if((shmptr = shmat(shmid,0,0)) == (void *)-1)  
        {  
        printf("shmat error!\n");  
        exit(1);  
        }  
      
        while(1)  
        {  
        printf("string :%s\n",shmptr);  
        sleep(3);  
        }  
      
        exit(0);  
    }  



    展开全文
  • Linux下共享内存编程

    千次阅读 2011-08-12 15:26:49
    利用共享内存(Share Memory)可以让我们在任意两个进程之间传递数据,而且也是相对容易实现的一种方法,在正常情况下,一个进程所使用的内存是不允许其它进程访问的,但是通过共享内存可以实现数据的共享。...
    利用共享内存(Share Memory)可以让我们在任意两个进程之间传递数据,而且也是相对容易实现的一种方法,在正常情况下,一个进程所使用的内存是不允许其它进程访问的,但是通过共享内存可以实现数据的共享。
    

           使用共享内存用到的API函数有:

    # include <sys/types.h>

    #include <sys/ipc.h>

    #include <sys/shm.h>

    key_t ftok(const char *pathname, int proj_id)

    其中pathname为当前进程的程序名,第二个参数为进程所开辟的第几个共享内存,返回一个key_t值,用于共享内存的获取使用。

    int shmget(key_t shmkey, int shmsiz, int flag)

    void *shmat(int shmid, char *shmaddr, int shmflag)

    int shmdt(char *shmaddr)

    shmget是用来创建或者指向一块共享内存的函数,其中shmkey是共享内存的标识符,如果父子关系的进程间通信的话,这个标识用IPC_PRIVATE替代,如果没有任何关系,可以使用ftok计算出来;Shmsiz是这块内存的大小;flag是这块内存的模式和权限标识(IPC_CREAT, IPC_ALLOC, IPC_EXCL,0666权限)。函数成功返回共享内存的shmid,否则返回-1表示失败。

    Shmat用来允许进程访问共享内存的函数,其中shmid是共享内存的ID,shmaddr是共享内存起始位置,shmflag是本进程对内存操作模式,SHM_RDONLY是只读模式,成功返回共享内存的起始位置。

    Shmdt与shmat相反,是用来禁止进程访问一块共享内存的函数。

    int shmctl(int shmid, int cmd, struct shmid_ds *buf)

    其中shmid是共享内存的ID,cmd是控制命令(IPC_STAT, IPC_SET, IPC_RMID),struct shmid_ds *buf是一个结构体指针,如果要改变共享内存的状态,使用它来指定,获得状态就存放在这个结构体中。

    上述API函数的详细说明请使用man(男人)查看:

    # man shmget | shmat | shmdt | shmctl

     

    下面使用一个简单的例子说明如何使用共享内存。

    // sharememcut.c  拷贝用户输入的字符串到共享内存中

    #include <sys/types.h>

    #include <sys/ipc.h>

    #include <sys/shm.h>

    #include <stdio.h>

     

    int main()

    {

        key_t shmkey;

        int shmid, in_tmp;

        char *head, *pos, in_data[4096], *in_ptr;

        // Create share memory KEY

        shmkey = ftok("sharememcut", 1);

        // Get the share memory ID

        shmid = shmget(shmkey, sizeof(in_data), IPC_CREAT | 0666);

        // Allow the process to access share memory, and get the address

        head = pos = shmat(shmid, 0, 0);

        in_ptr = in_data;

        // Receive the character from stdin, 'q' to quit

        while ((in_tmp = getchar()) != 'q') {

           *in_ptr = in_tmp;

           in_ptr++;

        }

     

         *in_ptr = '\0';

         in_ptr = in_data;

     

        // Cut the data into share memory

        while (*in_ptr != '\0') {

            *pos++ = *in_ptr++;

        }

     

        // Prohabit the process to access share memory

        shmdt(head);

     

        return 0;

    }

    # gcc -o sharememcut sharememcut.c  编译sharememcut.c

    # ./sharememcut    执行sharememcut创建共享内存

    # ipcs -m | grep 4096   查看创建的共享内存

    0x01068288 348848145  root      666        4096       0 

     

    // sharemempaste.c 将共享内存的内容显示在屏幕上并且删除共享内存

    #include <sys/types.h>

    #include <sys/ipc.h>

    #include <sys/shm.h>

    #include <stdio.h>

     

    int main()

    {

        key_t shmkey;

        int shmid;

        char *head, *pos, out_data[4096], *out_ptr;

        // Create share memory KEY

        shmkey = ftok("sharememcut", 1);

        // Get the share memory ID

        shmid = shmget(shmkey, sizeof(out_data), 0666);

           if (shmid == -1)

               return -1;

        // Allow the process to access share memory, and get the address

        head = pos = shmat(shmid, 0, 0);

        out_ptr = out_data;

        // Get the data from share memory

        while (*pos != '\0') {

            *out_ptr++ = *pos++;

        }

        *out_ptr = '\0';

        // Output the data into stdout

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

        fflush(stdout);

     

        // Prohabit the process to access share memory

        shmdt(head);

        // Delete the share memory

        shmctl(shmid, IPC_RMID, NULL);

     

        return 0;

    }

     

    # gcc -o sharemempaste sharemempaste.c  编译sharemempaste.c

    # ./sharemempaste  执行程序显示共享内存的内容

     

    陷阱请参考:http://www.ibm.com/developerworks/cn/aix/library/au-cn-sharemem/
    展开全文
  • 共享内存相对于分布式内存编程哟个很大的好处是数据是共享的,即所有的CPU都可以访问的到。而不是像分布式内存编程那样,当需要数据交互时,得通过进程通信来完成《我的并行计算之路(二)MPI点对点通信》、《...

     共享内存,可以理解为多个CPU连接在一个内存上,内存上的数据供所有CPU访问和修改。与之对应的概念是分布式内存编程,详见我之前的博客《我的并行计算之路(一)Ubuntu 16.04下的MPI安装》。共享内存相对于分布式内存编程哟个很大的好处是数据是共享的,即所有的CPU都可以访问的到。而不是像分布式内存编程那样,当需要数据交互时,得通过进程通信来完成《我的并行计算之路(二)MPI点对点通信》《我的并行计算之路(三)MPI集合通信》《我的并行计算之路(四)MPI集合通信》。此外共享内存和分布式内存编程还有一个很大的不同,就是分布式内存运行的是进程,而共享内存运行的是线程。

    线程可以理解为“轻量级的进程”。进程是一个可拥有资源的独立单位又是一个可以独立调度和分派的单位,因此其才成为一个能独立运行的基本单位。然而,成也萧何,败也萧何,也正是进程又拥有资源又可以被独立调度和分派,因此操作系统在进程切换的时候需要花费大量的时间和空间开销,不仅需要保存和设置寄存器内容,还需要涉及存储器管理方面的工作。因此,若能将进程的两个属性分开,由操作系统分开处理,程序的并发性会更好。亦即,对于作为调度和分派的基本单位,其不作为拥有资源的单位,以做到“轻装上阵”,减少时空开销;而作为拥有资源的基本单位,不对其做频繁的切换。这样的思想便形成了线程的概念。也就是说,线程作为调度和分派的基本单位,在切换时,只需保存和设置少量寄存器,而进程作为拥有资源的单位,保存了绝大多数的资源数据。在引入了线程的操作系统中,通常一个进程拥有若干个线程,至少也有一个线程。这些线程只拥有一点必不可少的资源,主要资源依靠访问其隶属的进程获得。此外,引入线程的另一个好处是一个进程中的多个线程具有相同的地址空间,在同步和通信的实现方面线程也比进程容易。当然,在同一个进程中的线程切换不会引起进程的切换,但从一个进程中的线程切换到另一个进程的线程仍会引起进程的切换。

    我使用的是POSIX线程库,也常称为Pthreads线程库,其是类Unix系统(Linux, Mac OS等)上的标准库(C 语言),定义了一套多线程的编程的应用程序接口(API)。广泛使用的多线程库还有Java threads、Windows threads和Solaris threads。首先我们来看一下一个简单的多线程程序,该程序在各个线程中打印线程号和线程总数:

     

    #include<bits/stdc++.h>
    #include<pthread.h>
    using namespace std;
    
    int thread_count = 0;
    
    void* hello(void* rank)
    {
    	long my_rank = (long)rank;
    	printf("Hello from thread %ld of %d\n", my_rank, thread_count);
    	return NULL;
    }
    
    int main(int argc, char* argv[])
    {
    	long thread;
    	pthread_t* thread_handles = NULL;
    	
    	thread_count = strtol(argv[1], NULL,10);
    	
    	thread_handles = (pthread_t*)malloc(thread_count*sizeof(pthread_t));
    	
    	for(thread = 0; thread < thread_count; thread++){
    		pthread_create(&thread_handles[thread], NULL, hello, (void*)thread);
    	}
    	
    	for(thread = 0; thread < thread_count; thread++){
    		pthread_join(thread_handles[thread], NULL);
    	}
    	
    	free(thread_handles);
    	thread_handles = NULL;
    	
    	return 0;
    }

    下面,详细解释一下这个程序。程序包含了pthread.h文件,是Pthreads线程库的头文件。首先定义了一个全局变量thread_count,用来记录线程数量。在Pthreads程序中,全局变量被所有线程共享,函数中的局部变量由执行该函数的线程所私有,为了避免混淆以及出现奇怪的结果,建议不要将全局变量和局部变量起一样的名字。主函数中的long thread是用来给线程编号的。函数strtol是用来将字符串转换为长整形的:

     

     

    long strtol(
    		const char*		number_p,
    		char**			end_p,
    		int				base
    		)
    

    返回由number_p所指向的字符串转换得到的长整形数,参数base是表达这个整数值所用的基(进位计数制),如果end_p不是NULL,它就指向number_p字符串的第一个无效字符(非数值字符)。得到了线程数量后,就要用malloc为每个线程的Pthread_t对象分配内存,Pthread_t是一个声明好的数据结构,用来存储线程的专有信息。这些线程的Pthread_t对象组成一个数组,thread_handles指向首地址。接下里就要创建线程了,使用的是pthread_create函数:

     

     

    int pthread_create(
    		Pthread_t*		thread_p,
    		const pthread_attr_t*			attr_p,
    		void*				(*start_routine)(void*),
    		void*			arg_p,
    		)

    其中,第一个参数是一个指针,指向对应的Pthread_t对象(注意,Pthread_t对象在pthread_create函数调用前就要给其分配内存),第二个参数一般为NULL,第三个参数表示将要运行的函数,第四个参数表示指向第三个参数中运行函数的参数。在创建了线程后,线程就交由操作系统来进行调度和分派了,我们无法决定某个线程在某个核上运行。线程运行完成后,需要将各个线程结束,我们队每个线程调用pthread_join函数,该函数将等待对应的线程结束。

     

     

    int pthread_join(
    		Pthread_t		thread,
    		void**			ret_val_p
    		)

    其中,第一个参数为一个Pthread_t对象,第二个参数可以接受对应线程的返回值。大家可以想象一下整个过程,pthread_create创建出多个线程,然后pthread_join函数将各个线程合并在一起(join)。

    然后编译,g++ (或者 Intel 编译器 icpc):

    g++ -pthread -o 程序文件名.out 程序文件名.cpp

    执行程序

    ./程序文件名.out


     

     

     

     

     

    展开全文
  • Linux关于共享内存编程

    千次阅读 2007-03-05 14:48:00
    程序运行后,分为父子进程,子进程申请共享内存,然后等待父进程继续执行,父进程首先等待子进程申请到共享内存标识,然后输出共享内存中的内容,为了演示共享内存可以随时更新,程序中在子进程里产生随机数写入共享...
  • linux c 共享内存编程学习记录

    千次阅读 2012-01-17 15:56:03
    unix/linux 环境下,IPC的方式有3种: 消息队列、信号、共享内存 #include #include 共享内存使用方法(shared memory),主要使用以下这几个函数: 1) ftok 根据一个文件路径(相应的文件必须存在)和...
  • 共享内存编程模型

    千次阅读 2013-09-24 15:18:00
    1.什么是共享内存编程模型?2.共享内存有哪几种实现方式?2.1 mmap的实现方式2.2 System V API2.3 POSIX API 3. 源码分析4. 总结 5. References 1. 什么是共享内存? 硬件的视角来看共享内存:在一个多处理机系统...
  • OpenMP共享内存并行编程详解

    千次阅读 2017-04-02 11:36:39
     平行计算机可以简单分为共享内存和分布式内存,共享内存就是多个核心共享一个内存,目前的PC就是这类(不管是只有一个多核CPU还是可以插多个CPU,它们都有多个核心和一个内存),一般的大型计算机结合分布式内存和...
  • UNIX网络编程共享内存

    千次阅读 2016-05-17 17:32:01
    IPC形式除了管道、FIFO、信号量以外,还有共享内存区和消息队列。这里主要堆共享内存进行介绍。 共享内存区是可用IPC形式中最快的。一旦这样的内存区映射到共享它的进程地址空间,这些进程间数据的传递就不再涉及...
  • 共享内存区是可用IPC形式中最快的。一旦内存区映射到共享它的进程的地址空间,进程间数据的传递就不再涉及内核。然而往该共享内存区存放信息或从中取走信息的进程间通常需要某种形式的同步。不再涉及内核是指:进程...
  • Linux 高级编程 - 共享内存 Shared Memory

    千次阅读 2017-09-06 10:22:32
    Linux 高级编程 - 共享内存 Shared Memory
  • Windows核心编程共享内存

    千次阅读 2016-11-10 10:09:00
    Windows共享数据和信息的机制:RPC、COM、OLE、DDE、窗口消息、剪贴板、邮箱、管道、套接字以及内存映射文件。 内存映射:通过让两个或多个进程映射同一个文件。(在进程空间中保留一个地址空间区域,将物理存储器...
  • 上一篇博文提到的系统调用mmap通过映射一个普通文件实现共享内存。那么本文中介绍的System V 共享内存则是通过映射特殊文件系统shm中的文件实现进程间的共享内存通信。也就是说,每个共享内存区域对应特殊文件系统...
  • Linux编程,进程间通信,共享内存

    千次阅读 2018-05-31 19:22:20
    此次给大家分享的是Linux下通过共享内存,实现进程间的通信,流程如下: 创建写进程,其功能为创建共享内存并映射到私有地址空间,然后向内存写入数据,直至遇到’#’为止,读进程使用和写进程相同的KEY创建共享...
  • 在前面介绍了system v 共享内存的相关知识,现在来稍微看看posix 共享内存 和系列函数。 共享内存简单来说就是一块真正的物理内存区域,可以使用一些函数将这块区域映射到进程的地址空间进行读写,而posix 共享内存...
  • 1、Posix提供了两种在无亲缘关系进程间共享内存区的方法: (1)内存映射文件:先有open函数打开,然后调用mmap函数把得到的描述符映射到当前进程地址空间中的一个文件(上一篇博文所用到的就是)。 (2)共享...
  • 共享内存 最为高效的进程间通信方式   ...进程直接读写内存,不需要任何数据的拷贝 ... •为了在多个进程间交换信息,内核专门留出了一块内存区 ... •由需要访问的进程将其映射到自己...l共享内存编程步骤:  1.
  • linux网络编程共享内存简介和mmap 函数

    千次阅读 多人点赞 2013-06-14 20:11:02
    一、共享内存简介 共享内存区是最快的IPC形式,这些进程间数据传递不再涉及到内核,换句话说是进程不再通过执行进入内核的系统调用来传递彼此的数据。 即每个进程地址空间都有一个共享存储器的映射区,当这块区域...
  • 对于像管道和消息队列等通信方式,则需要在内核和用户空间进行四次的数据拷贝,而共享内存则只拷贝两次数据[1]:一次从输入文件到共享内存区,另一次从共享内存区到输出文件。实际上,进程之间在共享内存时,并不...
  • 共享内存 通信原理:在内中开辟一块空间,进程可以写入内容和读取内容完成通信,但是每次写入内容会覆盖之前内容。 实现方法 from multiprocessing import Value,Array obj = Value(ctype,data) 功能 : ...
  • 1. 内核共享内存 编程模型:  1.1.创建共享内存,得到一个ID shmget 1.2.把ID影射成虚拟地址(挂载) shmat  1.3.使用虚拟地址访问内核共享内存使用任何内存函数与运算符号 1.4.卸载虚拟地址 shmdt  1.5....
  • 共享内存定义 共享内存是被多个进程共享的一部分物理内存。共享内存是进程间通信的最快的一种方式。一个进程向共享内存区域中写入了数据,共享这个内存区域的所有进程可以立即看到其中的内容。   二 共享内存...
  • 跟消息队列一样,共享内存也有自己的数据结构,如下: struct shmid_ds { struct ipc_perm shm_perm; /* Ownership and permissions */ size_t  shm_segsz; /* Size of segment (bytes) */ time_t  shm_atime; /...
  • Linux下C编程共享内存通信实例

    千次阅读 2016-05-09 23:21:50
    共享内存是LUNIX 系统中最底层的通信机制,也是最快速的通信机制。共享内存通过两个或多个进程共享同一块内存区域来实现进程间的通信。通常是由一个进程创建一块共享 内存区域,然后多个进程可以对其进行访问,一个...
  • 共享内存区是最快的IPC形式。一旦这样的内存映射到共享它的进程的地址空间,这些进程间数据传递不再涉及到内核,换句话说是进程不再通过执行进入内核的系统调用来传递彼此的数据(如图)。 共享内存和其他进程间通信...
  • 共享内存是允许两个或多个进程共享同一块内存区域
  • [编程开发]如何使用共享内存

    千次阅读 2009-11-28 10:21:00
    共享内存作为一种IPC,用于进程间通信,甚至可以实现用户程序与内核间的数据交换。现在我们就简单介绍一下共享内存的几个系统调用。创建第一步要做的是创建一个共享内存结构。#include #include int shmget (key_t ...
  • 针对分布式内存系统,可以采用MPI进行编程,这里主要是针对共享内存系统亦即本地多核主机进行并行编程。 这里采用拉格朗日公式粗略地计算PI, 虽然这个公式收敛很慢,但这里仅仅是作为学习并行编程的一个...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 297,257
精华内容 118,902
关键字:

共享内存编程