在多线程场景中正确锁定 List

15 浏览
0 Comments

在多线程场景中正确锁定 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()?

归根结底,我正在寻找一种表达“好的,这个列表现在是我的,所有其他线程必须等待,直到我完成它”的方法。

0