2013-04-22 3 views
3

Я реализую некоторую файловую систему на C++. До сих пор я использовал fstream, но я понял, что его невозможно открыть в эксклюзивном режиме. Поскольку существует много потоков, я хочу разрешить несколько чтений, а при открытии файла в режиме записи я хочу открыть файл в эксклюзивном режиме?
Каков наилучший способ сделать это? Я думаю, Boost предлагает некоторые функции. И есть ли другая возможность? Я также хотел бы видеть простой пример. Если это нелегко/полезно делать на C++, я мог бы написать и на C.Как открыть файл в эксклюзивном режиме в C++

Я использую Windows.

+1

материал Такой низкоуровневый лучше всего сделано в C, с минимальными накладными расходами как возможно ... –

+1

@ bash.d Чепуха, почему вы так думаете? Весь смысл C++ заключается в предоставлении абстракций с надбавкой. Я заставил тебя привязаться к кому-то, кто знал это. –

+1

@KonradRudolph Я не знаю о вас, но я не знаю о многих файловых системах, реализованных на C++ ... –

ответ

0

Ну, вы можете вручную предотвратить открытие файла, если он уже был открыт в режиме записи. Просто отследите, какие файлы вы открыли в режиме записи.

Возможно, вы можете указать имя файла и сохранить его в таблице после открытия с доступом для записи. Это позволит быстро найти, открыт ли файл или нет.

+0

Я не уверен, что это лучшая идея, потому что мне придется хранить все открытые файлы. (Обратите внимание, что если один файлA открыт в режиме чтения, и кто-то хочет открыть его в режиме записи, ему нужно будет подождать, пока не будет выполнен режим чтения). – rank1

2

На многих операционных системах это просто невозможно, поэтому C++ не поддерживает его. Вам нужно будет написать свой собственный streambuf. Если единственная платформа, о которой вы беспокоитесь, это Windows, вы можете использовать эксклюзивный режим для открытия, который он предлагает. Более вероятно, однако, вы хотели бы использовать какой-то файл замок, который является более точным, и доступен на большинстве, если не все платформы (но не переносимо — вам нужно LockFileEx под Windows, fcntl под Unix).

Под Posix вы также можете использовать pthread_rwlock. Butenhof дает реализацию с использованием классических мьютексов и переменных условий, которые присутствуют в C++ 11, поэтому вы могли бы реализовать портативную версию (при условии, что все читатели и писатели находятся в том же процессе — Posix запросы будут работать через границы процесса, но это не истинно для примитивов с потоком C++).

+0

Как и почему я должен писать свой собственный streambuf? Я думаю, мне будет проще использовать это окно api, как здесь http://msdn.microsoft.com/en-us/library/windows/desktop/aa365204(v=vs.85).aspx – rank1

+0

@SebastianCygert The Windows API требует вывода буфера 'char'; Интерфейс 'ostream' обрабатывает форматирование и преобразование в строки. Класс streambuf является мостом между ними. –

1

Если ваше приложение работает только в Windows, функция win32 API «CreateFile()» - ваш выбор.

Например: HANDLE hFile = :: CreateFileW (lpszFileFullPathName, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL);

+0

например: HANDLE hFile = :: CreateFileW (lpszFileFullPathName, GENERIC_WRITE, \t FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL); – skyfree

+0

Вы хотите отредактировать свой ответ и добавить свой пример туда. –

0

Вы можете переименовать файл, обновить его под новым именем и переименовать его. Я сделал это, но это немного тяжело.

0

Если вы открыты для использования boost, то я предлагаю вам использовать класс file_lock. Это означает, что вы хотите сохранить имя файла для файлов, которые вы открываете/закрываете, потому что fstream не делает этого для вас.

Они имеют два режима lock(), которые можно использовать для записи (то есть только один такой замка на время совместного использования блокировки предотвращает блокировку тоже) и lock_sharable(), которые вы можете использовать для чтения (т.е. любого количество потоков может получить такое замок).

Обратите внимание, что в конечном итоге вы сочтете это сложным для управления, прочитайте и напишите, таким образом. То есть, если всегда есть кто-то, чтобы прочитать, закрываемый замок никогда не может быть освобожден. В этом случае эксклюзивный замок никогда не получит шанс взять ....

// add the lock in your class 
#include <boost/interprocess/sync/file_lock.hpp> 
class my_files 
{ 
... 
private: 
    ... 
    boost::file_lock  m_lock; 
}; 

Теперь, когда вы хотите получить доступ к файлу, вы можете заблокировать его так или иначе. Если поток отвечает за это, вы можете добавить функции для доступа пользователя к блокировке. Если реализация функции чтения и записи в my_files отвечают, вы хотите, чтобы получить стек на основе объекта, который блокирует и разблокирует для вас (RAII):

class safe_exclusive_lock 
{ 
public: 
    safe_exclusive_lock(file_lock & lock) 
     : m_lock_ref(lock) 
    { 
     m_lock_ref.lock(); 
    } 
    ~safe_exclusive_lock() 
    { 
     m_lock_ref.unlock(); 
    } 
private: 
    file_lock & m_lock_ref; 
}; 

Теперь вы можете безопасно заблокировать файл (т.е. вы замок, делать то, что может бросить, вы всегда разблокировать перед выходом из вашего текущего {} -блок):

ssize_t my_files::read(char *buf, size_t len) 
{ 
    safe_exclusive_lock guard(m_lock); 
    ...your read code here... 
    return len; 
} // <- here we get the unlock() 

ssize_t my_files::write(char const *buf, size_t len) 
{ 
    safe_exclusive_lock guard(m_lock); 
    ...your write code here... 
    return len; 
} // <- here we get the unlock() 

file_lock использует файл, так что вы хотите, чтобы файл fstream уже создан, когда создается file_lock , Если файл fstream не может быть создан в конструкторе, вы, вероятно, хотите, чтобы преобразовать переменную m_lock в уникальном указателе:

private: 
    std::unique_ptr<file_lock> m_lock; 

И когда вы ссылаться на него, теперь нужна звездочка:

safe_exclusive_lock guard(*m_lock); 

Обратите внимание, что в целях безопасности, вы должны проверить, является ли указатель действительно выделяется, если не определено, это означает, что файл еще не открыт, так что я хотел бы предложить вам бросить:

if(m_lock) 
{ 
    safe_exclusive_lock guard(*m_lock); 
    ...do work here... 
} 
else 
{ 
    throw file_not_open(); 
} 
// here the lock was released so you cannot touch the file anymore 

В е е открытое, вы создаете замок:

bool open(std::string const & filename) 
{ 
    m_stream.open(...); 
    ...make sure it worked... 
    m_lock.reset(new file_lock(filename)); 
    // TODO: you may want a try/catch around the m_lock and 
    //  close the m_stream if it fails or use a local 
    //  variable and swap() on success... 
    return true; 
} 

И не забудьте освободить объект блокировки в ваших близких:

void close() 
{ 
    m_lock.reset(); 
} 
+0

Связанный [boost interprocess_lock не работает с несколькими процессами] (http://stackoverflow.com/questions/6697704/boost-interprocess-file-lock-does-not-work-with-multiple-processes) –

Смежные вопросы