Mic*_*tum 24 .net c# multithreading
好吧,我无法正确理解多线程场景.很抱歉再次提出类似的问题,我只是在互联网上看到许多不同的"事实".
public static class MyClass {
private static List<string> _myList = new List<string>;
private static bool _record;
public static void StartRecording()
{
_myList.Clear();
_record = true;
}
public static IEnumerable<string> StopRecording()
{
_record = false;
// Return a Read-Only copy of the list data
var result = new List<string>(_myList).AsReadOnly();
_myList.Clear();
return result;
}
public static void DoSomething()
{
if(_record) _myList.Add("Test");
// More, but unrelated actions
}
}
Run Code Online (Sandbox Code Playgroud)
想法是,如果激活录制,则对DoSomething()的调用将记录在内部List中,并在调用StopRecording()时返回.
我的规格是这样的:
通常的方式似乎是:
public static void DoSomething()
{
object _lock = new object();
lock(_lock){
if(_record) _myList.Add("Test");
}
// More, but unrelated actions
}
Run Code Online (Sandbox Code Playgroud)
或者,声明一个静态变量:
private static object _lock;
public static void DoSomething()
{
lock(_lock){
if(_record) _myList.Add("Test");
}
// More, but unrelated actions
}
Run Code Online (Sandbox Code Playgroud)
但是,这个答案说这并不妨碍其他代码访问它.
所以我想知道
在一天结束时,我正在寻找一种方式表达"好吧,这个列表现在是我的,所有其他线程必须等到我完成它".
Hen*_*man 32
我将锁定_myList本身,因为它是私有的,但使用单独的变量更常见.要改进几点:
public static class MyClass
{
private static List<string> _myList = new List<string>;
private static bool _record;
public static void StartRecording()
{
lock(_myList) // lock on the list
{
_myList.Clear();
_record = true;
}
}
public static IEnumerable<string> StopRecording()
{
lock(_myList)
{
_record = false;
// Return a Read-Only copy of the list data
var result = new List<string>(_myList).AsReadOnly();
_myList.Clear();
return result;
}
}
public static void DoSomething()
{
lock(_myList)
{
if(_record) _myList.Add("Test");
}
// More, but unrelated actions
}
}
Run Code Online (Sandbox Code Playgroud)
请注意,此代码用于lock(_myList)
同步对_myList 和 _record的访问.而且你需要同步这两个上的所有动作.
并且同意这里的其他答案,lock(_myList)
对_myList没有任何作用,它只使用_myList作为标记(可能是HashSet中的键).通过使用相同的令牌询问权限,所有方法都必须公平.另一个线程上的方法仍然可以使用_myList而不先锁定,但结果不可预测.
我们可以使用任何令牌,因此我们经常创建一个令牌:
private static object _listLock = new object();
Run Code Online (Sandbox Code Playgroud)
然后使用lock(_listLock)
而不是lock(_myList)
到处都是.
如果myList已经公开,那么这种技术是可取的,如果你重新创建myList而不是调用Clear(),那将是绝对必要的.
Jon*_*eet 15
在创建新锁DoSomething()
将肯定是错的-这将是毫无意义的,因为每次调用DoSomething()
会使用不同的锁.您应该使用第二种形式,但使用初始化程序:
private static object _lock = new object();
Run Code Online (Sandbox Code Playgroud)
确实,锁定不会阻止任何其他内容访问您的列表,但除非您直接公开列表,否则无关紧要:无论如何都不会访问列表.
是的,您可以以相同的方式将Start/StopRecording包装在锁中.
是的,设置一个布尔变量是原子的,但这不会使它成为线程安全的.如果你只访问同一个锁中的变量,那么你在原子性和波动性方面都很好.否则,您可能会看到"陈旧"值 - 例如,您将值设置为true
一个线程,另一个线程在读取时可以使用缓存值.
有几种方法可以锁定列表.您可以直接锁定_myList,前提是_myList永远不会更改为引用新列表.
lock (_myList)
{
// do something with the list...
}
Run Code Online (Sandbox Code Playgroud)
您可以专门为此目的创建锁定对象.
private static object _syncLock = new object();
lock (_syncLock)
{
// do something with the list...
}
Run Code Online (Sandbox Code Playgroud)
如果静态集合实现System.Collections.ICollection接口(List(T)),则还可以使用SyncRoot属性进行同步.
lock (((ICollection)_myList).SyncRoot)
{
// do something with the list...
}
Run Code Online (Sandbox Code Playgroud)
要理解的要点是你想要一个且只有一个对象用作你的锁定sentinal,这就是为什么在DoSomething()函数中创建锁定sentinal不起作用的原因.正如Jon所说,每个调用DoSomething()的线程都会获得自己的对象,因此该对象的锁定每次都会成功并立即授予对该列表的访问权限.通过使锁定对象保持静态(通过列表本身,专用锁定对象或ICollection.SyncRoot属性),它将在所有线程之间共享,并且可以有效地序列化对列表的访问.
归档时间: |
|
查看次数: |
35515 次 |
最近记录: |