Bob*_*obC 0 c# multithreading locking
我的问题与下面的代码有关.我简化了代码来提炼问题.
我知道锁保持foo Hashtable变量不被改变,但是锁之外的变量呢?我们在代码中看到一些奇怪的行为,看起来像这样,这就是出现的问题.感谢您的任何意见.
using System.Collections;
namespace MultithreadScratch01
{
public class ThreadFoo
{
public void Foo(Stub2 stub2, Hashtable foo)
{
Stub1 bar;
var prop1 = stub2.Prop1;
var prop2 = stub2.Prop2;
var prop3 = stub2.Prop3;
var hash = string.Format("{0}_{1}_{2}", prop1, prop2, prop3);
lock(foo)
{
if(!foo.Contains(hash))
{
bar = new Stub1 {Foo = "some arbitrary string", Bar = 123};
foo.Add(hash, bar);
}
}
}
public class Stub1
{
public string Foo { get; set; }
public int Bar { get; set; }
}
public class Stub2
{
public string Prop1 { get; set; }
public string Prop2 { get; set; }
public string Prop3 { get; set; }
}
}
}
Run Code Online (Sandbox Code Playgroud)
你在这里做的是多种方式的"最糟糕的做法".
首先,无法保证引用该哈希表的其他线程在读取或写入之前也将其锁定.这就是为什么这种技术如此糟糕; 这种保证很难做到.
其次,无法保证引用该哈希表实例的其他线程没有锁定它并且因为它们有缺陷或恶意而无法解锁它.您可能会让其他人负责您的代码的正确性,这是一个危险的位置.一个好的规则是"永远不会锁定外部代码可以看到的任何东西".永远不要锁定"this",永远不要锁定Type对象,等等.有时会对该规则作出例外,但我想要一个很好的理由.
这里正确的做法是首先使用ConcurrentDictionary.如果你不能这样做,那么我会写一个围绕HashTable的包装器:
sealed class ThreadSafeHashTable
{
private readonly HashTable hashTable = new HashTable();
public void Add(object key, object value)
{
lock(this.hashTable)
{
...
Run Code Online (Sandbox Code Playgroud)
现在锁定是(1)总是在每次调用Add时完成,并且(2)只有此类中的代码可能会获取锁定,因为被锁定的对象是私有的并且永远不会被传递出去.
只有你不能做到这两件事的任何一件事,我才会这么做.如果你想以艰难的方式去做,那么你将不得不追踪哈希表可能使用的每一个地方,并确保写入正确的锁定代码.
说这个并不完全正确 lock
保持foo Hashtable变量不被更改
只是; 锁定在同一个对象上的两个线程不能同时在锁内.如果你有任何不在 lock同一个对象(哈希表)上的代码,它会直接进入,很可能造成损害.重新考虑其他变量......如果有什么东西在改变对象,并且没有锁定你所在的同一个锁对象,那么事情就会变得质朴.其实,有哪怕一些边缘的情况下是同一个对象锁定(这将可以解决我的移动性能,读取里面的lock).但是,由于这些变量未被"捕获",因此一旦您拥有值的快照,快照就不会更改.