关于C#:内存映射文件的类,线程和引用计数

Memory mapped file class, threads and reference counting

我正在整理一个类,我要调用文件。

文件对象仅包含指向内存映射文件的指针和链接。

构造函数获取一个文件,并将该文件映射到内存范围。总而言之
有点像这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class file
{
  public:
   file(unsigned char* filename) { open(filename); }        

   open(unsigned char* filename)
   {
       /// snip
       length_ = fstat(.....)
       file_ = mmap(.....)
   }
  private:
   unsigned int length_;
   unsigned char* bytes_;
};

现在,可以复制该文件对象。

乐趣来了。通常,像这样的类将需要深度复制构造函数来复制bytes_。但是,我很满意我可以复制指针,因为内存是共享的,并且无论如何它应该查看相同的文件。我不要
重新映射文??件。但是,很明显,在某些情况下要防止内存泄漏bytes_
需要释放。

我可以使用哪些机制来决定何时删除内存和munmap?

我当时正在考虑使用boost :: shared_ptr以便仅在最后一个引用时释放析构函数中的内存,但是我必须使用互斥锁来保护它吗?
我已经可以使用一些便捷的boost功能了吗?我不想引入另一个大库,这不是一个选择。

1
2
3
4
5
6
7
8
9
10
11
boost::shared_ptr<unsigned char> bytes_;

~file()
{
    // enter some sort of critical section
    if (bytes_.unique()){
      munmap(bytes_);
      bytes_ = 0;
    }
    // exit critical section
}


我会做些不同。

问题在于shared_ptr并非要处理数组,然后正如您所说的那样,存在那些同步问题。

简单的替代方法是使用Pimpl习惯用语:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class FileImpl: boost::noncopyable
{
public:
  FileImpl(char const* name): mLength(fstat(name)), mFile(mmap(name)) {}
  ~FileImpl() { munmap(mFile); }

  unsigned int GetLength() const { return mLength; }
  unsigned char* GetFile() const { return mFile; }
private:
  unsigned int mLength;
  unsigned char* mFile;
};

class FileHandle
{
public:
  FileHandle(char const* name): mFile(new FileImpl(name)) {}

  void open(char const* name) { mFile = new FileImpl(name); }

private:
  boost::shared_ptr<FileImpl> mFile;
};

在销毁过程中,您将不会有任何同步问题(由shared_ptr自然处理)。

您可能还希望使用Factory,因为多次创建具有相同文件名的各种FileHandle对象将导致多次调用mmap,并且我不确定这不会复制内存中的文件。另一方面,在这种情况下,集中调用的工厂可以简单地返回已经创建的FileHandle对象的副本。


shared_ptr是线程安全的,如注释中张贴的链接编号所述。

另一种选择是将复制构造函数和赋值运算符声明为私有,从而允许(强制?)用户根据自己的情况选择适当的管理策略,例如shared_ptr或ptr_container。添加移动语义以进一步提高灵活性。


查看Boost提供的互斥锁(和其他同步机制)。看到这个。另外,Boost有一个线程库。您是否在使用特定于操作系统的线程库?如果是这样,Boost.Threads可能值得一看。另外,您的file对象不应该位于共享内存中。传递指针对我来说似乎并不危险。