如果我有一个需要从多个线程访问的非线程安全对象(例如NetworkStream),则可以安全地持有一个用于锁定的对象,以保护该非线程安全对象。一个ConcurrentDictionary(或常规Dictionary)的值中的安全对象?
即这样,我可以有多个线程,每个线程都试图将数据写入客户端的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);
}
}
}
答案 0 :(得分:-1)
在这种情况下,字典和互斥锁可能通常都不是必需的。通常,您使用私有对象互斥锁,以避免死锁。这样,其他任何代码都无法尝试对此进行锁定。但是在这种情况下,互斥对象及其所用的东西实际上都是 public 。
如果每个线程都能够在ClientStreams和互斥对象上运行锁定/解锁,则它们无法实现其目的。无论什么,您都可以锁定“ ClientStream”实例。
或者,使用类型为object和ClientStream的类,结构或tupel。这样,您至少可以将Mutex和hte ClientStream同时使用。
答案 1 :(得分:-1)
经过测试,即可正常运行。感谢大家的热烈交谈。当运行下面的示例代码时,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");
}
}