Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 锁定时的System.ArgumentException_C#_Multithreading_Locking - Fatal编程技术网

C# 锁定时的System.ArgumentException

C# 锁定时的System.ArgumentException,c#,multithreading,locking,C#,Multithreading,Locking,在我的实际应用程序中,我需要迭代集合,但它可以从其他线程更改。所以我需要复制集合以对其进行迭代。我把这个问题复制到一个小例子中,但显然我对锁和线程的理解不足导致了System.ArgumentException。用锁尝试了不同的事情,但结果是一样的 class Program { static List<int> list; static void Main(string[] args) { list = new List<int>

在我的实际应用程序中,我需要迭代集合,但它可以从其他线程更改。所以我需要复制集合以对其进行迭代。我把这个问题复制到一个小例子中,但显然我对锁和线程的理解不足导致了
System.ArgumentException
。用锁尝试了不同的事情,但结果是一样的

class Program
{
    static List<int> list;
    static void Main(string[] args)
    {
        list = new List<int>();
        for (int i = 0; i < 1000000; i++)
        {
            list.Add(i);
            if (i == 1000)
            {
                Thread t = new Thread(new ThreadStart(WorkThreadFunction));
                t.Start();
            }
        }
    }

    static void WorkThreadFunction()
    {
        lock (list)
        {
            List<int> tmp = list.ToList();  //Exception here!
            Console.WriteLine(list.Count);
        }
    }
}
类程序
{
静态列表;
静态void Main(字符串[]参数)
{
列表=新列表();
对于(int i=0;i<1000000;i++)
{
列表.添加(i);
如果(i==1000)
{
线程t=新线程(新线程开始(WorkThreadFunction));
t、 Start();
}
}
}
静态void WorkThreadFunction()
{
锁(列表)
{
List tmp=List.ToList();//此处出现异常!
Console.WriteLine(list.Count);
}
}
}

选项1:

以下是您的代码的修改版本:

class Program
{
    static List<int> list;
    static void Main(string[] args)
    {
        list = new List<int>();
        for (int i = 0; i < 1000000; i++)
        {
            lock (list) //Lock before modification
            {
                list.Add(i);
            }
            if (i == 1000)
            {
                Thread t = new Thread(new ThreadStart(WorkThreadFunction));
                t.Start();
            }

        }

        Console.ReadLine();
    }

    static void WorkThreadFunction()
    {
        lock (list)
        {
            List<int> tmp = list.ToList();  //Exception here!
            Console.WriteLine(list.Count);
        }
    }
}

并删除所有
lock
语句。

我发现您的算法中存在一些问题,可能您应该重构它。在使用
ConcurrentBag
类的情况下,您应该意识到,将整个集合复制到新集合只是为了枚举,这是一项非常庞大且非常耗时的操作,在此过程中,您无法有效地操作集合

lock (list)
{
    // VERY LONG OPERATION HERE
    List<int> tmp = list.ToList();  //Exception here!
    Console.WriteLine(list.Count);
}
锁(列表)
{
//这里的运作时间很长
List tmp=List.ToList();//此处出现异常!
Console.WriteLine(list.Count);
}
你真的不应该
锁定
集合这么长的时间-在
for
循环结束时,你有很多线程彼此阻塞。此方法必须使用,不应直接使用
线程

您可以选择的另一种情况是,通过对集合版本进行双重检查,甚至通过存储集合的快照并在集合访问的方法中进行检查,来实现其中的一些


我认为你提供的信息不足以建议你解决问题的正确方法。

尝试了乔尔的建议。这个包很慢。在数百万次迭代中锁定似乎效率低下。在这种情况下,事件等待句柄似乎很好(比在我的电脑上使用锁所花费的时间少3倍)

类程序
{
静态列表;
静态ManualResetEventSlim mres=新的ManualResetEventSlim(错误);
静态void Main(字符串[]参数)
{
列表=新列表();
对于(int i=0;i<10000000;i++)
{
列表.添加(i);
如果(i==1000)
{
线程t=新线程(新线程开始(WorkThreadFunction));
t、 Start();
mres.Wait();
}
}
}
静态void WorkThreadFunction()
{
List tmp=List.ToList();
Console.WriteLine(list.Count);
mres.Set();
}
}

工作正常,但这会使程序的执行速度降低近5倍。我们如何仅在需要复制列表时阻止它,而不是在每次添加操作时阻止它百万次?您是否尝试过使用来自的线程安全集合?您可以使用
ConcurrentBag
并移除
锁。您可以比较执行性能。使用ConcurrentBag,执行时间甚至比不使用锁的情况长17倍,比使用锁的情况长3倍:(@Dork,你还在用
ConcurrentCollection
锁定某些东西吗?这样的性能损失并不常见。@VMAtm否。删除了所有锁定的语句并将列表更改为ConcurrentBag该异常的消息是什么?实际上我真正的程序很少需要查询集合,所以开销不会很大,但感谢链接,我发现了l很多事情。如果是这样的话,你肯定必须正确定义你的算法,可能是在集合的各个部分上进行迭代。完美。我现在可以对集合进行计数,然后使用for循环对其进行迭代。(在我的情况下,如果在读取时添加元素,这不是问题)。int n=list.Count.list.take(n)抛出相同的异常,因此我需要使用for循环而不是LINQ,但这没关系。只需添加
Wait()
Set()
将导致主线程在运行
WorkThreadFunction()
时被阻塞。您将始终看到
列表。Count
为1001(直到调用
Set()
)因为您的线程现在已同步。这意味着在
WorkThreadFunction
完成之前,不会对列表执行任何添加操作。
lock (list)
{
    // VERY LONG OPERATION HERE
    List<int> tmp = list.ToList();  //Exception here!
    Console.WriteLine(list.Count);
}
 class Program
{
    static List<int> list;
    static ManualResetEventSlim mres = new ManualResetEventSlim(false);

    static void Main(string[] args)
    {
        list = new List<int>();
        for (int i = 0; i < 10000000; i++)
        {
            list.Add(i);

            if (i == 1000)
            {
                Thread t = new Thread(new ThreadStart(WorkThreadFunction));
                t.Start();
                mres.Wait();
            }
        }
    }

    static void WorkThreadFunction()
    {
        List<int> tmp = list.ToList();
        Console.WriteLine(list.Count);
        mres.Set();
    }
}