我是否可以安全地尝试从两个不同的线程创建相同的目录,而不让其中一个线程引发异常或遇到其他问题?
请注意,根据MSDN的说法,在已经存在的目录上调用CreateDirectory()
是可以的,在这种情况下,该方法将不执行任何操作。
Directory.CreateDirectory
调用本身可以安全地从多个线程进行。如果你这样做,它不会破坏程序或文件系统状态
但是,不能以这种方式调用Directory.CreateDirectory
来保证它不会抛出异常。文件系统是一个不可预测的野兽,它可以在任何时候被你无法控制的其他程序更改。例如,很有可能看到以下情况发生
- 程序1线程1:
c:tempfoo
调用CreateDirectory
成功 - 程序2线程1:删除程序1用户对
c:temp
的访问 - 程序1线程2:由于访问不足,调用
CreateDirectory
并引发
简而言之,您必须假设Directory.CreateDirectory
,或者实际上是任何涉及文件系统的函数,可以并且将相应地抛出和处理。
来自目录上的MSDN文档:
此类型的任何公共静态(在Visual Basic中共享)成员都是线程安全的。任何实例成员都不能保证是线程安全的。
因此,由于CreateDirectory是静态的,是的,它是线程安全的。
也就是说:正如@JaredPar所指出的,线程安全问题并不是方法可以抛出异常的唯一原因。文件系统调用可能引发异常的原因有很多(在任何情况下,无论是否是多线程的),您都需要考虑这些原因。
说它是线程安全的,我(和MSDN)只是暗示了对它的字面解释,意思是"这种方法不会以可能导致无效状态、竞争条件或其他通常与不安全的多线程代码相关的不利影响的方式修改共享程序状态"
要详细说明@JaredPar的答案,您手头有一个种族条件。如果第一次调用完全创建了文件夹,然后第二次调用才开始,那么一切都会好起来
然而,如果第二个调用到达操作系统,而操作系统仍在处理第一个调用,则操作系统可能会因为锁定问题而使第二个失败,并且您将得到一个异常。
它仍然是线程安全的,因为你不会创建任何不可预测的文件夹,或者根本没有文件夹。
更详细地说,虽然我不能100%确定当同一个文件夹同时创建两次时,Windows是否没有内部竞争条件,但我很确定你不能通过这样做来破坏磁盘,或者在两个创建都被卡住的情况下陷入僵局。其中一个将成功,另一个将失败,但文件夹将被创建。
所以你的启发法,只是为了绝对确定,应该是这样的:
- 创建目录
- 如果失败,请随机等待一段时间(例如0.2到0.5秒),然后重试
-
如果它经常失败(比如说,连续3次),你就会遇到另一个问题——没有文件夹权限,磁盘满了等等
顺便说一句,为什么不在应用程序开始运行时创建一次文件夹呢?