在多线程场景中正确锁定 List?
在多线程场景中正确锁定 List?
好的,我只是无法正确理解多线程场景。对于再次提出类似问题的问题,我很抱歉,我只是在互联网上看到了许多不同的“事实”。
public static class MyClass { private static List_myList = new List ; private static bool _record; public static void StartRecording() { _myList.Clear(); _record = true; } public static IEnumerable StopRecording() { _record = false; // 返回列表数据的只读副本 var result = new List (_myList).AsReadOnly(); _myList.Clear(); return result; } public static void DoSomething() { if(_record) _myList.Add("Test"); // 更多但无关的操作 } }
这个想法是,如果激活了Recording,对DoSomething()的调用将记录在内部列表中,并在调用StopRecording()时返回。
我的规范是:
- 不认为StartRecording是线程安全的。用户在没有其他线程调用DoSomething()时应该调用它。但如果它在某种程度上是线程安全的话,那就太棒了。
- StopRecording也不是官方线程安全的。同样,如果它能够线程安全,那将是很好的,但这不是必须的。
- DoSomething必须是线程安全的。
通常的方法似乎是:
public static void DoSomething() { object _lock = new object(); lock(_lock){ if(_record) _myList.Add("Test"); } // 更多但无关的操作 }
或者,声明一个静态变量:
private static object _lock; public static void DoSomething() { lock(_lock){ if(_record) _myList.Add("Test"); } // 更多但无关的操作 }
然而,这个答案说这不能防止其他代码访问它。
所以我想知道:
- 我应该如何正确地锁定一个列表?
- 我应该在我的函数中创建锁对象还是作为静态类变量?
- 我可以将Start和StopRecording的功能包装在一个锁块中吗?
- StopRecording()执行两个操作:将布尔变量设置为false(以防止DoSomething()添加更多内容),然后复制列表以将数据的副本返回给调用者)。我假设_record = false; 是原子性的,并且会立即生效?所以通常情况下,我不需要担心多线程问题,除非其他线程再次调用StartRecording()?
归根结底,我正在寻找一种表达“好的,这个列表现在是我的,所有其他线程必须等待,直到我完成它”的方法。