在多线程方案中正确锁定List?好吧,我无法正确处理多线程方案。很抱歉再次提出类似的问题,我刚刚在互联网上看到了许多不同的“事实”。publicstaticclassMyClass{privatestaticList_myList=newList;私有静态布尔_record;publicstaticvoidStartRecording(){_myList.Clear();_record=真;}publicstaticIEnumerableStopRecording(){_record=false;//返回列表数据的只读副本varresult=newList(_myList).AsReadOnly();_myList.Clear();返回结果;}publicstaticvoidDoSomething(){if(_record)_myList.Add("测试");//更多但不相关的操作}}这个想法是,如果记录被激活,对DoSomething()的调用将记录在内部列表中,并在调用StopRecording()时返回。我的规格是这样的:通常的方式似乎是:publicstaticvoidDoSomething(){object_lock=newobject();锁(_lock){if(_record)_myList.Add("测试");}//更多但不相关的操作}或者,声明一个静态变量:privatestaticobject_lock;publicstaticvoidDoSomething(){lock(_lock){if(_record)_myList.Add("测试");}//更多但不相关的操作}但是,这个答案表示它不会阻止其他代码访问它。所以我想知道。在一天结束时,我正在寻找一种方式来表达“好吧,这个列表现在是我的了,所有其他线程都必须等到我完成它”。我将锁定_myList本身,因为它是私有的,但更常见的是使用单独的变量。几点需要改进:publicstaticclassMyClass{privatestaticList_myList=newList;私有静态布尔_record;publicstaticvoidStartRecording(){lock(_myList)//锁定列表{_myList.Clear();_record=真;}}publicstaticIEnumerableStopRecording(){lock(_myList){_record=false;//返回列表数据的只读副本varresult=newList(_myList).AsReadOnly();_myList.Clear();返回结果;}}publicstaticvoidDoSomething(){lock(_myList){if(_record)_myList.Add("测试");}//更多但不相关的操作}}请注意,此代码使用lock(_myList)来同步对_myList和_record的访问。并且您需要同步这两个上的所有操作。为了同意这里的其他答案,lock(_myList)对_myList没有任何作用,它只是使用_myList作为标签(可能是HashSet中的键)。所有方法都必须公平,通过使用相同的令牌来请求权限。另一个线程上的方法仍然可以在不先锁定的情况下使用_myList,但结果不可预知。我们可以使用任何令牌,所以我们经常创建一个:privatestaticobject_listLock=newobject();然后到处使用lock(_listLock)而不是lock(_myList)。如果myList已经公开,则建议使用此技术,如果您重新创建myList而不是调用Clear(),则此技术是绝对必要的。在DoSomething()中创建一个新锁绝对是错误的——这毫无意义,因为每次调用DoSomething()都会使用不同的锁。您应该使用第二种形式,但使用初始化程序:privatestaticobject_lock=newobject();确实,锁不会阻止其他任何东西访问您的列表,但除非您直接公开该列表,否则这无关紧要:无论如何,这两个列表都不会被访问。是的,您可以用同样的方式将Start/StopRecording包裹在锁中。是的,设置布尔变量是原始的,但这并不能使其成为线程安全的。如果您只访问同一个锁中的变量,那么您可以同时使用原语和易变性。否则,您可能会看到“陈旧”的值——例如,您在一个线程中将一个值设置为true,而另一个线程在读取时可能会使用缓存的值。有几种方法可以锁定列表。您可以直接锁定_myList,前提是_myList永远不会更改为引用新列表。lock(_myList){//对列表做一些事情...}您可以专门为此目的创建锁对象。私有静态对象_syncLock=newobject();lock(_syncLock){//dosomethingwiththelist...}如果静态集合实现了System.Collections.ICollection接口(List(T)),也可以使用SyncRoot属性Synchronize来完成。lock(((ICollection)_myList).SyncRoot){//对列表做一些事情...}要理解的要点是你希望一个且只有一个对象用作你的锁哨兵,这就是为什么在DoSomething()函数中创建锁的sentinal不起作用的原因。正如Jon所说,每个调用DoSomething()的线程都会获得自己的对象,因此该对象的锁定每次都会成功并立即授予对列表的访问权限。通过使锁对象静态(通过列表本身、专用锁对象或ICollection.SyncRoot属性),它将在所有线程之间共享,并且可以有效地序列化对列表的访问。第一种方法是错误的,因为每个调用者都会锁定不同的对象。您可以锁定列表。lock(_myList){_myList.Add(...)}你可能误解了这个答案,实际上是说他们的lock语句实际上并没有锁定有问题的对象不被修改,而是阻止任何其他代码使用该对象作为锁源执行。这实际上意味着当您使用与锁定对象相同的实例时,不应执行锁定块内的代码。从本质上讲,您并不是真的要“锁定”您的列表,您是在尝试拥有一个通用实例,当您想要修改列表、使用它或当您想要修改列表时,您可以将其用作参考点想要“锁定”防止执行可能修改列表的其他代码。以上就是C#学习教程:MultiThreaded方案中List的正确锁定?如果所有分享的内容对你有用,需要进一步了解C#学习教程,希望大家多多关注。本文收集自网络,不代表立场。如涉及侵权,请点击右侧联系管理员删除。如需转载请注明出处:
