CreateDirectory () в C # потокобезопасен? - PullRequest
14 голосов
/ 05 марта 2012

Могу ли я попытаться создать один и тот же каталог из одного и того же из двух разных потоков, не вызывая исключения из одного из них, или столкнуться с другими проблемами?

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

Ответы [ 3 ]

15 голосов
/ 05 марта 2012

Сам вызов Directory.CreateDirectory можно сделать из нескольких потоков. Это не повредит состояние программы или файловой системы, если вы это сделаете.

Однако невозможно вызвать Directory.CreateDirectory таким образом, чтобы гарантировать, что оно не вызовет исключения. Файловая система - это непредсказуемый зверь, который может быть изменен другими программами вне вашего контроля в любой момент времени. Например, очень возможно увидеть следующее:

  • Программа 1 Поток 1: Вызовите CreateDirectory для c:\temp\foo, и это успешно
  • Программа 2, поток 1: Удаляет доступ к c:\temp из программы 1, пользователь
  • Программа 1 Поток 2: Вызов CreateDirectory и выбрасывание из-за недостаточного доступа

Короче говоря, вы должны предположить, что Directory.CreateDirectory, или действительно любая функция, которая касается файловой системы, может и будет генерировать и обрабатывать соответственно.

6 голосов
/ 05 марта 2012

Из документов MSDN в каталоге :

Любые открытые статические (Shared в Visual Basic) члены этого типа являются поточно-ориентированными.Ни один из членов экземпляра не гарантированно является потокобезопасным.

Поэтому, поскольку CreateDirectory является статическим, да, он является потокобезопасным.

При этом : как указывает @JaredPar, проблемы безопасности потоков не единственная причина, по которой метод может генерировать исключения.Существует множество причин, по которым вызов файловой системы может вызвать исключение (при любых обстоятельствах, многопоточное или нет), и вам необходимо учитывать это.

Говоря, что это потокобезопасный, я (и MSDN) подразумеваем только очень буквальную интерпретацию этого, то есть «этот метод не изменяет общее состояние программы таким образом, что это может привести к недопустимому состоянию, условиям гонки или другим условиям».неблагоприятные последствия, обычно связанные с небезопасным многопоточным кодом "

4 голосов
/ 05 марта 2012

Чтобы уточнить ответ @ JaredPar, у вас в руках расы.Если первый вызов полностью создает папку, и только после этого начинается второй вызов, все будет в порядке.

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

Это по-прежнему потокобезопасно в том смысле, что вы не создадите никаких непредсказуемых папок или папок вообще.

Чтобы уточнить - хотя я не уверен на 100%, что Windows не имеет внутреннего состояния гонки, когда одна и та же папка создается дважды одновременно, я почти уверен, что вы не сможете очистить диск, выполнив это,или зайдите в тупик, когда оба творения будут застрять.Один из них будет успешным, другой не удастся, но папка будет создана.

Таким образом, ваша эвристика, чтобы быть абсолютно уверенной, должна быть такой:

  • Создать каталог
  • Если произойдет сбой, подождите случайное количество времени (скажем, от 0,2 до 0,5 секунды) и повторите попытку.
  • Если произойдет сбой постоянно (скажем, 3 раза застрока), у вас есть другая проблема - нет прав доступа к папке, целому диску и т. д.

    Кстати, почему бы не создать папку один раз при запуске приложения?

...