我是否可以请求任何响应者只考虑“纯粹的”C / C ++(无论这意味着什么)? STL还可以。提升不是。
我正在编写自己的C ++内存池类(在Linux系统上),用于在共享内存中分配和释放C ++对象。我需要这个来访问多个进程中的相同对象。我将使用POSIX信号量控制对内存池对象操作的访问,但我有一个基本的分配/解除分配问题。我的代码只适用于从同一个池分配的相同大小的对象。目前,我们可以动态地忽略与池的增长和收缩相关的问题。
考虑到我为一共MAXFOOOBJECTS Foo对象定义了一个共享内存段。我以下列方式定义共享内存段:
int shmid = shmget (somekey, ((sizeof(Foo) + 4) * MAXFOOOBJECTS) + 4, correctFlags);
void* sMem = shmat (shmid, (void*)0, 0);
通过使用此共享内存的所有进程,内存将被解释为:
struct SharedMemStructure
{
int numberOfFooObjectsInPool;
Foo* ptrArray [MAXFOOOBJECTS]; // Pointers to all the objects in the array below
Foo objects [MAXFOOOBJECTS]; // Same as the value in the shmget call
};
让我们说我有一个Foo定义的对象:
<Foo.h>
class Foo
{
public:
Foo ();
~Foo ();
void* operator new (); // Will allocate from shared memory
void operator delete (void* ptr); // Will deallocate from shared memory
private:
static void* sharedMem; // Set this up to be a POSIX shared memory that accesses
// the shared region in memory
static int shmid;
}
<Foo.cpp>
int Foo::shmid = shmget (somekey, ((sizeof(Foo) + 4) * MAXFOOOBJECTS) + 4, correctFlags);
void* Foo::sharedMem = shmat (shmid, (void*)0, 0);
void* Foo::operator new ()
{
void* thisObject = NULL;
sem_wait (sem); // Implementation of these is not shown
// Pick up the start of a chunk from sharedMem (will make sure this
// chunk has unused memory...
thisObject = (sharedMem + 4 + 4 * MAXFOOOBJECTS +
(sizeof (Foo) * sharedMem->numberOfFooObjectsInPool);
sharedMem->ptrArray[numberOfFooObjectsInPool] = thisObject;
sharedMem->numberOfFooObjectsInPool ++;
sem_post (sem);
return thisObject;
}
void Foo::operator delete (void* ptr)
{
int index = 0;
sem_wait (sem); // Implementation of these is not shown
// Swap the deleted item and the last item in the ptrArray;
index = (ptr - (sharedMem + 4 + (4*MAXFOOOBJECTS)))/(sizeof(Foo));
ptrArray[index] == ptrArray[numberOfFooObjectsInPool - 1];
numberOfFooObjectsInPool --;
sem_post (sem);
}
现在,我的问题是:
答案 0 :(得分:3)
我发现你的想法没问题,但你的指针算术有点麻烦......而且非便携式也是如此。 一般来说,你永远不应该访问一个结构的成员,添加以前成员的大小,因为这是完全不可移植的(而且非常难看)。请记住,编译器可能对结构的成员有对齐限制,因此它可以在任何适合的位置插入填充字节。
使用您提供的struct SharedMemStructure
更容易:
int shmid = shmget (somekey, sizeof(SharedMemStructure), correctFlags);
SharedMemStructure* sharedMem = static_cast<SharedMemStructure*>(shmat (shmid, (void*)0, 0));
然后在operator new
:
//...
thisObject = &sharedMem[sharedMem->numberOfFooObjectsInPool];
//...
关于您的问题:
ptrArray
成员并使用每个空闲槽的第一个字节构建一个空闲槽列表,指向下一个免费的。答案 1 :(得分:3)
将所有文字4替换为sizeof(int)和sizeof(Foo *),以实现可移植性和可读性。或者更好的是,实际使用您定义的SharedMemStructure。
然后,更改SharedMemStructure,然后开始使用它。用于跟踪使用哪些插槽的算法存在缺陷。一旦删除了一个项目,并且已经调整了指针列表,就无法知道在没有遍历整个列表的情况下使用了哪些插槽。一个简单的bool数组可以工作,它仍然需要遍历列表。
如果您真的关心O(n),则需要维护已使用和免费的链接列表。这可以使用单个固定大小的int数组来完成。
size_t indices[MAXFOOOBJECTS];
size_t firstUsedIndex;
size_t firstFreeIndex;
将firstUsedIndex初始化为MAXFOOOBJECTS,将firstFreeIndex初始化为0.索引通过MAXFOOOBJECTS初始化为1。这样,您可以将索引中的每个条目视为链接列表,其中内容是“下一个”值,MAXFOOOBJECTS是列表终止符。分配可以在恒定时间内完成,因为您可以获取列表的前端节点。解除分配将是线性的,因为您必须在使用的列表中找到节点。您可以使用(ptr-poolStart)/ sizeof(Foo)快速找到节点,但仍需要找到上一个节点。
如果您想要消除重新分配成本,请将索引的大小加倍并将其视为双向链接列表。代码类似,但现在你可以在恒定的时间内完成所有工作。
答案 2 :(得分:1)
这看起来像一个问题:
int main() {
Foo* a = new Foo; // a == &sharedMem->objects[0]
Foo* b = new Foo; // b == &sharedMem->objects[1]
// sharedMem->ptrArray: {a, b, ...}
delete a;
// sharedMem->ptrArray: {b, ...}
Foo* c = new Foo; // c == &sharedMem->objects[1] == b!
}