好吧,我只是无法正确理解多线程场景。抱歉再次问类似的问题,我只是在互联网上看到许多不同的“事实”。
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
}
}
这个想法是,如果激活了 Recording,对 Do Something() 的调用就会记录在内部列表中,并在调用 Stop Recording() 时返回。
我的规格是这样的:
- StartRecording 不被视为线程安全的。用户应该在没有其他线程调用 DoSomething() 时调用此方法。但如果能以某种方式实现,那就太好了。
- StopRecording 也不是正式的线程安全的。再说一遍,如果可以的话那就太好了,但这不是必需的。
- DoSomething 必须是线程安全的
通常的方式似乎是:
public static void DoSomething()
{
object _lock = new object();
lock(_lock){
if(_record) _myList.Add("Test");
}
// More, but unrelated actions
}
或者,声明一个静态变量:
private static object _lock;
public static void DoSomething()
{
lock(_lock){
if(_record) _myList.Add("Test");
}
// More, but unrelated actions
}
然而,这个答案 https://stackoverflow.com/questions/230716/difference-between-locklocker-and-lockvariablewhichiamusing/230861#230861表示这不会阻止其他代码访问它。
所以我想知道
- 我如何正确锁定列表?
- 我应该在函数中创建锁对象还是作为静态类变量创建?
- 我可以将 Start 和 StopRecording 的功能也包装在锁块中吗?
- StopRecording() 做了两件事:将布尔变量设置为 false(以防止 DoSomething() 添加更多内容),然后复制列表以将数据的副本返回给调用者)。我假设 _record = false;是原子的并且会立即生效吗?所以通常我根本不必担心这里的多线程,除非其他线程再次调用 StartRecording() ?
归根结底,我正在寻找一种方式来表达“好吧,这个列表现在是我的了,所有其他线程都必须等到我完成它”。
我将在这里锁定 _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
}
}
请注意,此代码使用lock(_myList)
同步访问两个 _myListand_记录。并且您需要同步这两者上的所有操作。
并同意这里的其他答案,lock(_myList)
对 _myList 不执行任何操作,它只是使用 _myList 作为令牌(可能作为 HashSet 中的键)。所有方法都必须通过使用相同的令牌请求许可来公平竞争。另一个线程上的方法仍然可以使用 _myList 而无需先锁定,但结果不可预测。
我们可以使用任何令牌,因此我们经常专门创建一个令牌:
private static object _listLock = new object();
然后使用lock(_listLock)
代替lock(_myList)
到处。
如果 myList 是公开的,则该技术是可取的,并且如果您重新创建 myList 而不是调用 Clear(),则该技术是绝对必要的。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)