内存映射文件类、线程和引用计数

Posted

技术标签:

【中文标题】内存映射文件类、线程和引用计数【英文标题】:Memory mapped file class, threads and reference counting 【发布时间】:2010-08-17 09:11:10 【问题描述】:

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

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

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

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::shared_ptr<unsigned char> bytes_;

~file()

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

【问题讨论】:

刚刚注意到。所有班级成员都是私有的。 见***.com/questions/93073/… 【参考方案1】:

我会做的稍有不同。

问题是shared_ptr 不是用来处理数组的,然后就像你说的那样存在同步问题。

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

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 对象的副本。

【讨论】:

你需要在工厂中使用弱引用。 @chrispy:你可以。工厂的难点在于正确同步它以避免创建同一文件的多个内存副本。当最后一个FileHandle 死亡时,您可以选择是否立即释放文件,您可能希望让它保持活动状态,以防再次被要求。 @Matthieu 你仍然需要对弱引用做一些聪明的事情,否则你永远无法告诉它需要删除,因为共享指针永远不会超出范围。 @chrispy:你可以,或者你可以简单地lock; test unicity; reset; unlock;。当然你也不能使用shared_ptr。有很多选择,但我也认为,如果你想要一些简单的东西,那么使用弱引用是一个好主意。顺便说一句,听起来你有一个有趣的论文,我现在就深入研究它:) @Matthieu 享受吧!如果早期的理论章节过于沉重,其他章节没有它也很容易理解。 (确实,如果您涉足整个部分,您完全有可能是第一个!)【参考方案2】:

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

【讨论】:

它们存储在全局地图结构中。【参考方案3】:

shared_ptr 是线程安全的,正如评论中发布的链接所言。

另一种方法是将复制构造函数和赋值运算符声明为私有,允许(强制?)用户根据他们的情况选择适当的管理策略,例如 shared_ptr 或ptr_container。添加move semantics 以获得更大的灵活性。

【讨论】:

以上是关于内存映射文件类、线程和引用计数的主要内容,如果未能解决你的问题,请参考以下文章

检测引用计数对象中的内存泄漏

Java 虚拟机原理垃圾回收算法 ( Java 虚拟机内存分区 | 垃圾回收机制 | 引用计数器算法 | 引用计数循环引用弊端 )

Swift学习笔记-自动引用计数弱引用和无主引用

Swift学习笔记-自动引用计数弱引用和无主引用

Netty源码-内存泄漏检测toLeakAwareBuffer

自动引用计数