Класс отображенного в памяти файла, потоки и подсчет ссылок - PullRequest
1 голос
/ 17 августа 2010

Я собираю класс, я собираюсь вызвать файл.

Файловый объект просто содержит указатель на отображенный в памяти файл и ссылку.

Конструктор берет файл и отображает файл в диапазон памяти. В итоге это выглядит примерно так:

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
}

Ответы [ 3 ]

1 голос
/ 17 августа 2010

Я бы сделал это немного по-другому.

Проблема в том, что 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 в этом случае.

0 голосов
/ 17 августа 2010

shared_ptr является поточно-ориентированным, как указано в комментариях, указанных в комментарии.

Альтернативой может быть объявление конструктора копирования и оператора присваивания частным, что позволяет (заставляет?) Пользователя выбирать подходящую стратегию управления для своих обстоятельств, например shared_ptr или ptr_container . Добавьте семантику перемещения для дополнительной гибкости.

0 голосов
/ 17 августа 2010

Посмотрите на мьютексы (и другие механизмы синхронизации), которые предлагает Boost.Смотрите это .Кроме того, Boost имеет библиотеку потоков.Вы используете специфичную для ОС библиотеку потоков?Если это так, возможно, стоит взглянуть на Boost.Threads .Кроме того, ваш file объект не должен находиться в общей памяти.Обход указателя не выглядит для меня немного опасным.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...