用于在多线程环境中创建唯一目录的Synclock

时间:2014-10-03 09:48:25

标签: c# vb.net multithreading parallel-processing locking

在我的应用程序中,我正在创建报告。报告由并行运行的作业创建。报告需要存储在唯一的目录中。

据我了解,SyncLock块中的代码一次只能被一个线程调用。所以我想出了以下代码,用于从当前日期和时间以及计数器生成唯一路径:

修改:DirectoryLock定义为Private DirectoryLock As Object = New Object

'Create a non existant path
Dim ID As String 'Unique ID, that is added to the path
Dim RandomReportName As String 'The resulting directory name
SyncLock DirectoryLock 'Lock the creation of the directory, to avoid the same names
    Dim number As Integer = 0
    Do
        number += 1
        ID = Format(number, "000") 'Create ID from a counter
        RandomReportName = "Report_" & Format(Date.Now, "yyyy_MM_dd-HH_mm_ss.fff") & "_(" & ID & ")" 'Generate the path
        opts.OutputPath = IO.Path.Combine(opts.OutputPath, RandomReportName)
    Loop Until IO.Directory.Exists(opts.OutputPath) = False 'Increase the counter, until a non existant path is found
    IO.Directory.CreateDirectory(opts.OutputPath) 'Create the directory in the synclock, so other threads will need to find a new name (higher counter)
End SyncLock 'Free the code

据我了解,它应该有效。然而,当我同时并行地说10个作业时,经常发生多个线程获得相同的路径名并且我不明白为什么。

我缺少什么(因为必须有:-))以及如何避免这样的问题?

VB.NET或C#中的答案都非常受欢迎。

1 个答案:

答案 0 :(得分:0)

我在完全错误的一端搜索错误。

我认为锁不工作但是简单的错误是

opts.OutputPath = IO.Path.Combine(opts.OutputPath, RandomReportName)

我重复使用相同的变量进行连接。因此,在进一步的循环迭代中,新的RandomReportName将添加到现有的RandomReportName中。

解决方案当然是使用临时变量

'Create a non existant path
Dim ID As String
Dim RandomReportName As String
Dim ResultPath As String = "" 'Stores the unique path name
SyncLock DirectoryLock
    Dim number As Integer = 0
    Do
        number += 1
        ID = Format(number, "000") 'Create ID from a counter
        RandomReportName = "Report_" & Format(Date.Now, "yyyy_MM_dd-HH_mm_ss.fff") & "_(" & ID & ")" 'Generate the path
        ResultPath = IO.Path.Combine(opts.OutputPath, RandomReportName) 'Assign the result path with the combined base path and unique name
    Loop Until IO.Directory.Exists(ResultPath) = False
    IO.Directory.CreateDirectory(ResultPath)
    opts.OutputPath = ResultPath 'Store the temporary variable for further use
End SyncLock 'Free the code