4

我正在使用并发字典来保存打开的文件。

要打开一个新文件,我这样做:

myDictionary.GetOrAdd (fName, (fn) => new StreamWriter(fn, true));

有了这个,我经常得到以下异常:

System.IO.IOException: The process cannot access the file '....' because it is being used by another process.
   at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
   at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy, Boolean useLongPa
   at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, FileOptions options, String msgPath, Boolean bFromProxy, Boolean useLongPath, Boolean checkHost)
   at System.IO.StreamWriter..ctor(String path, Boolean append, Encoding encoding, Int32 bufferSize, Boolean checkHost)
   at System.IO.StreamWriter..ctor(String path, Boolean append, Encoding encoding, Int32 bufferSize)
   at System.IO.StreamWriter..ctor(String path, Boolean append)

对我来说,这意味着该操作不是原子的,并且该软件试图两次打开同一个文件。

有没有其他我可以使用的操作,这将是原子的?出于性能考虑,我想避免锁定。

4

3 回答 3

6

因为,正如 Ameen 指出的那样,保证键/值对只会被添加一次,你可以持有 a ConcurrentDictionary<string, Lazy<StreamWriter>>,并且值工厂应该Lazy<StreamWriter>通过传递LazyThreadSafetyMode.ExecutionAndPublication参数来构造 (第二个参数,在实例化委托之后)。这样,您可以限制每个文件的锁定,而无需锁定整个字典。

private static ConcurrentDictionary<string, Lazy<StreamWriter>> _myDictionary =
    new ConcurrentDictionary<string, Lazy<StreamWriter>>();

public static StreamWriter GetOrCreate(string fName)
{
    return _myDictionary.GetOrAdd(fName,
        new Lazy<StreamWriter>(() => new StreamWriter(fName),
            LazyThreadSafetyMode.ExecutionAndPublication)).Value;
}
于 2014-02-18T23:53:08.220 回答
3

这是意料之中的。字典本身可能是并发的,因为它提供对字典本身的线程安全访问,但是您涉及到并发字典边界之外的其他系统资源。Concurrent 字典不知道你在用流做什么。

我是否可以建议不要在这种情况下使用 a ,而是使用实例ConcurrentDictionary来包装调用。ReadWriterLockSlim这为您提供了读取锁(多个读取器),也可以升级为写入锁。因此,当您只需要阅读时,每个人都可以同时阅读,但在您需要写入的情况下 - 有一个坚固的锁到位。

于 2014-02-18T23:35:55.863 回答
1

您传递的值工厂方法可能会被调用多次,即使字典中只会存储一个值。我想不出一种方法ConcurrentDictionary来实现你想要的。

这是来自文档:

如果您在不同的线程上同时调用 GetOrAdd,则 addValueFactory 可能会被多次调用,但它的键/值对可能不会在每次调用时都添加到字典中。

http://msdn.microsoft.com/en-us/library/ee378677(v=vs.110).aspx

于 2014-02-18T23:42:35.163 回答