Как реализовать потокобезопасность для древовидной структуры, используемой для следующего сценария?

#c# #.net #windows #filesystems #dokan

#c# #.net #Windows #файловые системы #докан

Вопрос:

Я использую код C #, расположенный по следующим ссылкам, для реализации проекта Ram-disk.

В качестве резюме, приведенный выше код использует простую древовидную структуру для хранения каталогов, подкаталогов и файлов. В корне находится MemoryFolder объект, который хранит ноль или более объектов «MemoryFolder» и / или MemoryFile объектов. Каждый MemoryFolder объект, в свою очередь, хранит ноль или более MemoryFolder объектов и / или MemoryFile объектов и так далее до неограниченной глубины.

Однако код не является потокобезопасным. Какой самый элегантный способ реализации потокобезопасности? Кроме того, как следует применять следующий неисчерпывающий список требований к многопоточности для типичной файловой системы с помощью соответствующей стратегии блокировки?

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

  2. Ни одна из прямых или косвенных родительских папок папки, содержащей определенный файл (который в данный момент читается другим потоком), распространяющийся вплоть до корневой папки, не может быть перемещена или удалена другим потоком, пока ReadFile поток не завершит свое выполнение.

  3. Что касается каждого уникального файла, разрешает одновременный доступ для нескольких ReadFile потоков, но ограничивает доступ к одному WriteFile потоку.

  4. Если два отдельных ReadFile потока (запущенных почти одновременно), каждый из разных приложений пытается создать папку с тем же именем (при условии, что папка еще не существует до запуска обоих потоков), первый поток, который попадает на Ram-диск, всегда завершается успешно, а второй всегда завершается неудачей. Другими словами, порядок выполнения потоков является детерминированным.

  5. Метод вычисления общего дискового пространства GetDiskFreeSpace , выполняемый в отдельном потоке, не должен завершать свое выполнение, пока все WriteFile потоки, которые уже выполняются, не завершат его выполнение. Все последующие WriteFile потоки, которые не начали выполняться, блокируются до тех GetDiskFreeSpace пор, пока поток не завершит свое выполнение.

Ответ №1:

Самый простой способ сделать это — защитить все дерево с помощью ReaderWriterLockSlim. Это позволяет одновременный доступ для нескольких читателей или эксклюзивный доступ для одного автора. Любой метод, который каким-либо образом изменит структуру, должен будет получить блокировку записи, и никаким другим потокам не будет разрешено читать или записывать в структуру, пока этот поток не снимет блокировку записи.

Любой поток, который хочет прочитать структуру, должен получить блокировку чтения. Несколько считывателей могут получить блокировку чтения одновременно, но если поток хочет получить блокировку записи, что означает ожидание, пока не будут сняты все существующие блокировки чтения.

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

Если вы хотите поделиться этим между процессами, это уже другая история. Это ReaderWriterLockSlim не работает во всех процессах. Однако вы могли бы реализовать нечто подобное, используя комбинацию примитивов синхронизации, или создать драйвер устройства (или службу), который обслуживает запросы, тем самым сохраняя все это в одном процессе.