进程间通信方式包括了管道,消息队列,FIFO,共享内存,而共享内存是其中效率最高的。下图解释了其效率最高的原因(图片截取自《UNIX网络编程》)
我们可以看到上面的拷贝次数是4次,下面则是2次。
接下来我们看看使用,其实网上和书上都有了很多资料,API就是那么几个。
int shmget(key_t key,size_t size,int shmflag)。
key:可以指定IPC_PRIVATE,那么系统会为你创建一个key,并且返回一个id号。也可以通过ftok函数生成一个key(不了解ftok的童鞋可以动手man一下)。那么为什么要一个IPC既要一个key又有一个ID呢。这里我觉得是为了方便其他进程访问。进程A创建了一个共享内存,内核为其分配一个ID,这个时候进程B想要访问,他怎么获取这个ID(难道需要A把ID发送给B??)。但是我们用一个key就很方便了。事先A,B进程都知道这个key,那么A创建了,B就可以通过事先知道key找到这块内存。
size:共享内存的大小。如果是获得一块内存,则该值应该为0。
shmflag:读写权限的组合,可以与IPC_CREAT和IPC_EXCL按位或。当指定一个key时,IPC_CREAT和IPC_EXCL配合使用可以在存在该key的共享内存时返回-1。
当该函数调用成功后,返回一个系统分配的共享内存,并且size大小的字节被初始化为0
void *shmat(int shmid, const void *shmaddr, int shmflg)
有了一块共享内存后,进程需要映射该内存到进程的地址空间。这个函数就是作用。
shmid就是之前获得ID,shmaddr如果指定了,就会配合shmflg确定映射地址,不过一般都不这么干的。返回值就是获得的地址,你可以往里面写你或者读你需要的数据了。同时调用了该函数,系统会修改shmid_ds数据。
int shmdt(const void *shmaddr)
解除绑定关系,参数就是我们之前获取的那个返回地址。(其实我觉得这里参数如果为ID貌似更统一些吧)
int shmctl(int shmid, int cmd, struct shmid_ds *buf)
这个函数主要做一些修改和查询。比如设置锁,解锁,移除一块共享内存。
简单介绍了API,还要说一下一些注意的东西
1.共享内存不会把数据写入磁盘文件中,这个区别于mmap
2.即使没有进程绑定在共享内存,共享内存也不会消失的。必须通过shmctl或者ipcrm删除(或者更暴力的方式关掉电脑)
另外我们可能会考虑,系统最多创建多少个共享内存,一个进程最多可以绑定多少个内存,一个共享内存创建的size最大最小值是多少。其实这些设置在/proc/sys/kernel下面,我们也可以自己写程序来读取。贴一段代码用来获取上面的信息
#define MAX_SHMIDS 8196
int main(int argc,char *argv[])
{
int i,j;
int shmid[MAX_SHMIDS] = {0};
void *addr[MAX_SHMIDS] = {0};
//测试可以创建多少个共享内存
for ( i = 0;i < MAX_SHMIDS;++i )
{
shmid[i] = shmget(IPC_PRIVATE,1024,0666|IPC_CREAT);
if ( shmid[i] == -1 )
{
printf("create shared memory failed,max create num[%d],%s\r\n",i,strerror(errno));
break;
}
}
for ( int j = 0;j < i;++j )
{
shmctl(shmid[j],IPC_RMID,NULL);
}
//测试每个进程可以attach的最大数
for ( i = 0;i < MAX_SHMIDS;++i )
{
shmid[i] = shmget(IPC_PRIVATE,1024,0666|IPC_CREAT);
if ( shmid[i] != -1 )
{
addr[i] = shmat(shmid[i],0,0);
if ( addr[i] == (void *)-1 )
{
printf("process attach shared memory failed,max num[%d],%s\r\n",i,strerror(errno));
shmctl(shmid[i],IPC_RMID,NULL);
break;
}
}
else
{
printf("max num of process attach shared memory is[%d]\r\n",i-1);
break;
}
}
for ( j = 0;j < i;++j )
{
shmdt(addr[j]);
shmctl(shmid[j],IPC_RMID,NULL);
}
//测试一个共享内存创建最小的size
size_t size = 0;
for ( ;;size++ )
{
shmid[0] = shmget(IPC_PRIVATE,size,0666|IPC_CREAT);
if ( shmid[0] != -1 )
{
printf("create shared memory succeed,min size[%d]\r\n",size);
shmctl(shmid[0],IPC_RMID,NULL);
break;
}
}
//测试共享内存创建最大的size
for ( size = 65536;;size += 1024 )
{
shmid[0] = shmget(IPC_PRIVATE,size,0666|IPC_CREAT);
if ( shmid[0] == -1 )
{
printf("create shared memory failed,max size[%ld],%s\r\n",size,strerror(errno));
break;
}
shmctl(shmid[0],IPC_RMID,NULL);
}
exit(0);
}
好了,下篇开始介绍如何控制读写。
posted on 2012-09-06 19:26
梨树阳光 阅读(2206)
评论(0) 编辑 收藏 引用 所属分类:
Linux