C#多线程列表操作

And*_*Dog 5 c# multithreading atomic

如果我有这样的东西(伪代码):

class A
{
    List<SomeClass> list;

    private void clearList()
    {
        list = new List<SomeClass>();
    }

    private void addElement()
    {
        list.Add(new SomeClass(...));
    }
}
Run Code Online (Sandbox Code Playgroud)

当两个函数并行执行时,我是否可能遇到多线程问题(或任何类型的意外行为)?

用例是一个错误列表,可以随时清除(通过简单地分配一个新的空列表).

编辑:我的假设是

  • 只有一个线程添加元素
  • 被遗忘的元素是可以的(即清除和添加新元素之间的竞争条件),只要清除操作成功没有问题
  • .NET 2.0

Jon*_*eet 10

这里有两种可能的问题:

  • 新添加的项目最终可能会立即被遗忘,因为您清除并创建新列表.这是一个问题吗?基本上,如果AddElement同时ClearList调用和调用,则会出现竞争条件:元素将在新列表中结束,或者在旧的(遗忘的)列表中结束.
  • List<T>对于多线程变异是不安全的,因此如果两个不同的线程同时调用AddElement,则无法保证结果

鉴于您正在访问共享资源,我会在访问时亲自握住它.您仍然需要考虑在添加项目之前/之后立即清除列表的可能性.

编辑:我的评论是好的,如果你只是从一个线程添加已经有点可疑,原因有两个:

  • 有可能(我认为!)你最终可能会尝试添加到List<T>尚未完全构建的那个.我不确定,.NET 2.0内存模型(与ECMA规范中的模型相反)可能足够强大,可以避免这种情况,但这很难说.
  • 添加线程可能不会立即"看到"对list变量的更改,仍然会添加到旧列表中.实际上,没有任何同步,它可以永远看到旧的价值

当您在混合中添加"迭代"时,它变得非常棘手 - 因为您在迭代时无法更改列表.最简单的解决方案可能是提供一个返回列表副本的方法,UI可以安全地迭代:

class A
{
    private List<SomeClass> list;
    private readonly object listLock = new object();

    private void ClearList()
    {
        lock (listLock)
        {
            list = new List<SomeClass>();
        }
    }

    private void AddElement()
    {
        lock (listLock)
        {
            list.Add(new SomeClass(...));
        }
    }

    private List<SomeClass> CopyList()
    {
        lock (listLock)
        {
            return new List<SomeClass>(list);
        }
    }

}
Run Code Online (Sandbox Code Playgroud)