为了方便底层内存池的共享(重复一次,如果你在使用共享内存的话,这是很重要的),
在实例化
表
ACE_Malloc类还拥有一个映射(map)类型接口:可被给每个被分配的内存block一个名字,从而使它们可以很容易地被在内存池中查找的另一个进程找到。该接口含有bind()和find()调用。bind()调用用于给由malloc()调用返回给ACE_Malloc的block命名。find()调用,如你可能想到的那样,用于查找与某个名字相关联的内存。ACE_Malloc模板类时,有若干不同的内存池类可用(如表3-2所示)。这些类不仅可用于分配在进程内使用的内存,也可以用于分配在进程间共享的内存池。这也使得为何ACE_Malloc模板需要通过锁定机制来实例化显得更清楚了。当多个进程访问共享内存池时,该锁保证它们不会因此而崩溃。注意即使是多个线程在使用分配器,也同样需要提供锁定机制。3-2列出了各种可用的内存池:
池名
宏
描述
ACE_MMAP_Memory_Pool
ACE_MMAP_MEMORY_POOL
使用
<mmap(2)>创建内存池。这样内存就可在进程间共享了。每次更新时,内存都被更新到后备存储(backing store)。ACE_Lite_MMAP_Memory_Pool
ACE_LITE_MMAP_MEMORY_POOL
使用
<mmap(2)>创建内存池。不像前面的映射,它不做后备存储更新。代价是较低可靠性。ACE_Sbrk_Memory_Pool
ACE_SBRK_MEMORY_POOL
使用
<sbrk(2)>调用创建内存池。ACE_Shared_Memory_Pool
ACE_SHARED_MEMORY_POOL
使用系统
V <shmget(2)>调用创建内存池。Memory_Pool
内存可在进程间共享。
ACE_Local_Memory_Pool
ACE_LOCAL_MEMORY_POOL
通过
C++的new和delete操作符创建局部内存池。该池不能在进程间共享。
表
3-2 可用的内存池
下面的例子通过共享内存池使用
该例创建服务器进程,该进程创建内存池,再从池中分配内存。然后服务器使用从池中分配的内存来创建它想要客户进程“拾取”的消息。其次,它将名字绑定(
客户在开始运行后创建它自己的分配器,但是使用的是同一个内存池。这是通过将同一个名字传送到分配器的构造器来完成的,然后客户使用
ACE_Malloc类(该例使用ACE_SHARED_MEMORY_POOL来做演示,但表3-2中的任何支持内存共享的内存池都可以被使用)。bind)到这些消息,以使客户能使用相应的find操作来查找服务器插入池中的消息。find()调用来查找服务器插入的消息,并将它们打印给用户看。
例
3-2 #include "stdafx.h"
#include "ace/Malloc_T.h"
#include "ace/OS.h"
#include "ace/Null_Mutex.h"
#include "ace/MMAP_Memory_Pool.h"
#define DATA_SIZE 100
#define MESSAGE1 "Hiya over there client process"
#define MESSAGE2 "Did you hear me the first time?"
char poolname[8]="My_Pool";
typedef ACE_Malloc<ACE_MMAP_Memory_Pool/*ACE_SHARED_MEMORY_POOL*/,ACE_Null_Mutex> Malloc_Allocator;
static void server (void)
{
//Create the memory allocator passing it the shared memory
//pool that you want to use
Malloc_Allocator shm_allocator(poolname);
//Create a message, allocate memory for it and bind it with
//a name so that the client can the find it in the memory
//pool
char* Message1=(char*)shm_allocator.malloc(strlen(MESSAGE1));
ACE_OS::strcpy(Message1,MESSAGE1);
shm_allocator.bind("FirstMessage",Message1);
ACE_DEBUG((LM_DEBUG,"<<%s\n",Message1));
//How about a second message
char* Message2=(char*)shm_allocator.malloc(strlen(MESSAGE2));
ACE_OS::strcpy(Message2,MESSAGE2);
shm_allocator.bind("SecondMessage",Message2);
ACE_DEBUG((LM_DEBUG,"<<%s\n",Message2));
//Set the Server to go to sleep for a while so that the client has
//a chance to do its stuff
ACE_DEBUG((LM_DEBUG,
"Server done writing.. going to sleep zzz..\n\n\n"));
ACE_OS::sleep(2);
//Get rid of all resources allocated by the server. In other
//words get rid of the shared memory pool that had been
//previously allocated
shm_allocator.remove();
}
static void client(void)
{
//Create a memory allocator. Be sure that the client passes
// in the "right" name here so that both the client and the
//server use the same memory pool. We wouldn’t want them to
// BOTH create different underlying pools.
Malloc_Allocator shm_allocator(poolname);
//Get that first message. Notice that the find is looking up the
//memory based on the "name" that was bound to it by the server.
void *Message1;
if(shm_allocator.find("FirstMessage",Message1)==-1)
{
ACE_ERROR((LM_ERROR,
"Client: Problem cant find data that server has sent\n"));
ACE_OS::exit(1);
}
ACE_OS::printf(">>%s\n",(char*) Message1);
ACE_OS::fflush(stdout);
//Lets get that second message now.
void *Message2;
if(shm_allocator.find("SecondMessage",Message2)==-1)
{
ACE_ERROR((LM_ERROR,
"Client: Problem cant find data that server has sent\n"));
ACE_OS::exit(1);
}
ACE_OS::printf(">>%s\n",(char*)Message2);
ACE_OS::fflush(stdout);
ACE_DEBUG((LM_DEBUG,"Client done reading! BYE NOW\n"));
ACE_OS::fflush(stdout);
}
int main (int, char *[])
{
switch (ACE_OS::fork ())
{
case -1:
ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "fork"), 1);
case 0:
// Make sure the server starts up first.
ACE_OS::sleep (1);
client ();
break;
default:
server ();
break;
}
return 0;
}