Is CreateDirectory() in C# thread-safe?

2019-03-18 10:22发布

问题:

Can I safely attempt to create the same directory from two different threads, without having one of them throw an exception, or run into other issues?

Note that according to MSDN, it is OK to call CreateDirectory() on a directory which already exists, in which case the method is expected to do nothing.

回答1:

The Directory.CreateDirectory call itself is safe to make from multiple threads. It will not corrupt program or file system state if you do so.

However it's not possible to call Directory.CreateDirectory in such a way to guarantee it won't throw an exception. The file system is an unpredictable beast which can be changed by other programs outside your control at any given time. It's very possible for example to see the following occur

  • Program 1 Thread 1: Call CreateDirectory for c:\temp\foo and it succeeds
  • Program 2 Thread 1: Removes access to c:\temp from program 1 user
  • Program 1 Thread 2: Call CreateDirectory and throws due to insufficient access

In short you must assume that Directory.CreateDirectory, or really any function which touches the file system, can and will throw and handle accordingly.



回答2:

From the MSDN docs on Directory:

Any public static (Shared in Visual Basic) members of this type are thread safe. Any instance members are not guaranteed to be thread safe.

Therefore, as CreateDirectory is static, yes, it is thread safe.

That said: as @JaredPar points out, thread safety issues are not the only reason that a method can throw exceptions. There are a multitude of reasons why a filesystem call might throw an exception (under any circumstances, multithreaded or not), and you need to account for those.

By saying it is thread safe I (and MSDN) only imply the very literal interpretation of that, meaning "this method does not modify shared program state in a way that could cause invalid state, race conditions, or other adverse effects commonly associated with unsafe multithreaded code"



回答3:

To elaborate on @JaredPar's answer, you have a race condition on your hands. If the first call creates the folder completely, and only then the second call starts, everything will be OK.

however, if the second call reaches the OS while it is still processing the first, the OS might fail the second one dune to locking issues, and you will get an exception.

It is still thread safe in the sense that you won't get any unpredictable folders created, or no folder at all.

To elaborate - while I'm not 100% sure that Windows doesn't have an internal race condition when the same folder is created twice concurrently, I'm pretty certain you won't be able to trash the disk by doing that, or get a deadlock with both creations being stuck to death. One of them will succeed, the other will fail, but the folder will be created.

So your heuristics, just to be absolutely sure, should be this:

  • Create Directory
  • If it fails, wait a random amount of time (say, between 0.2 and 0.5 of a second) and try again.
  • If it fails constantly (say, 3 times in a row), you have another problem at your hands - no permissions to the folder, a full disk, etc..

    Incidentally, why not create the folder once when the application starts running?