c# - ConcurrentDictionary 的 GetOrAdd 不是原子的。除了锁定还有其他选择吗?

标签 c# multithreading concurrentdictionary

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

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

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)

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

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

最佳答案

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

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;
}

关于c# - ConcurrentDictionary 的 GetOrAdd 不是原子的。除了锁定还有其他选择吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21867842/

相关文章:

c# - 键盘助记符应该如何本地化?

c# - Maybe monad 如何充当短路?

Java - 可运行的线程未启动

c# - ConcurrentDictionary - AddOrUpdate 问题

c# - 使用 ANTLR 将 vbscript 翻译成 C#

c# - 删除选择器 XAMARIN 中的行

c# - 简单的多线程问题

c - 线程访问另一个线程的堆栈

c# - 我应该如何 "Cancel"ConcurrentDictionary 中的 AddOrUpdate?