包含要在锁定操作中使用的对象的字典

Dictionary containing objects to be used in lock operations

在我有一个需要从多个线程访问的非线程安全对象(例如 NetworkStream)的情况下,持有一个用于锁定的对象是否安全,以保护非-线程安全对象,在 ConcurrentDictionary(或常规字典)的值中?

即这样,我可以有多个线程,每个线程都尝试将数据写入客户端的 NetworkStream,但每次只允许一个?

我假设这是安全的,因为对象是引用类型,但希望有人能够确认。

使用 ConcurrentDictionary 的示例。 Send() 方法将由多个线程调用。目标是允许多个调用者拥有对 NetworkStream 的写访问权,我的好奇心是在这种情况下是否可以可靠地使用在 ConcurrentDictionary 的值中找到的对象进行锁定。

// Assume this is prepopulated
private ConcurrentDictionary<string, object> locks = ...

public void Send(string identifier, byte[] data)
{
  object clientLock = null;
  if (locks.TryGetValue(identifier, out clientLock))
  {
    lock (clientLock)
    {
      // assume we have the TcpClient here
      NetworkStream ns = client.GetStream();
      ns.Write(data, 0, data.Length);
    }
  }
}

在这种情况下,Dictionary 和 mutex 通常可能是不必要的。通常你使用 private object mutex 来避免死锁。这样就没有其他代码可以尝试获取对此的锁定。但在这种情况下,互斥对象和它所用的东西实际上都是 public.

如果每个线程都能够在 ClientStreams 和互斥体对象上 运行 lock/unlock,则它们无法实现其目的。您可以锁定 "ClientStream" 实例,无论它是什么。

或者,使用类型对象和 ClientStream 创建一个 class、结构或元组。这样你至少可以同时拥有 Mutex 和 hte ClientStream。

刚刚测试,它按预期工作。感谢大家的热烈讨论。 运行下面的示例代码时,Worker2被延迟了。

    static ConcurrentDictionary<string, object> locks = new ConcurrentDictionary<string, object>();

    static void Main(string[] args)
    {
        locks.TryAdd("foo", new object());
        Task.Run(() => Worker1());
        Task.Run(() => Worker2());
        Console.ReadKey();
    } 

    static void Worker1()
    {
        object lockObj = null;
        locks.TryGetValue("foo", out lockObj);
        lock (lockObj)
        {
            Console.WriteLine("Worker1");
            Thread.Sleep(10000);
        }
    }

    static void Worker2()
    {
        object lockObj = null;
        locks.TryGetValue("foo", out lockObj);
        lock (lockObj)
        {
            Console.WriteLine("Worker2"); 
        }
    }