Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/284.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# 同步收集线程安全_C#_Multithreading_Collections_Thread Safety - Fatal编程技术网

C# 同步收集线程安全

C# 同步收集线程安全,c#,multithreading,collections,thread-safety,C#,Multithreading,Collections,Thread Safety,我有System.Collections.Generic.SynchronizedCollection共享集合。我们的代码使用.NET4.0任务库跨线程并将同步的集合传递给线程。到目前为止,线程尚未向集合中添加或删除项。但是新的需求需要一个线程从集合中删除项,而另一个线程只读取集合。在从集合中删除项目之前是否需要添加锁?如果是这样,读线程是否是线程安全的?或者建议获得线程安全性的最佳方法?是的,SynchronizedCollection将为您执行锁定 如果您有多个读卡器而只有一个写卡器,您可能

我有System.Collections.Generic.SynchronizedCollection共享集合。我们的代码使用.NET4.0任务库跨线程并将同步的集合传递给线程。到目前为止,线程尚未向集合中添加或删除项。但是新的需求需要一个线程从集合中删除项,而另一个线程只读取集合。在从集合中删除项目之前是否需要添加锁?如果是这样,读线程是否是线程安全的?或者建议获得线程安全性的最佳方法?

是的,SynchronizedCollection将为您执行锁定

如果您有多个读卡器而只有一个写卡器,您可能希望使用ReaderWriterLock,而不是SynchronizedCollection


另外,如果您是.NET4+,请查看
System.Collections.Concurrent
。这些类的性能比SynchronizedCollection好得多。

不,它不是完全线程安全的。在一个简单的控制台应用程序中尝试以下操作,看看它是如何在异常情况下崩溃的:

var collection = new SynchronizedCollection<int>();

var n = 0;

Task.Run(
    () =>
        {
            while (true)
            {
                collection.Add(n++);
                Thread.Sleep(5);
            }
        });

Task.Run(
    () =>
        {
            while (true)
            {
                Console.WriteLine("Elements in collection: " + collection.Count);

                var x = 0;
                if (collection.Count % 100 == 0)
                {
                    foreach (var i in collection)
                    {
                        Console.WriteLine("They are: " + i);
                        x++;
                        if (x == 100)
                        {
                            break;
                        }

                    }
                }
            }
        });

Console.ReadKey();
var collection=newsynchronizedcollection();
var n=0;
任务。运行(
() =>
{
while(true)
{
集合。添加(n++);
睡眠(5);
}
});
任务。运行(
() =>
{
while(true)
{
Console.WriteLine(“集合中的元素:+collection.Count”);
var x=0;
if(collection.Count%100==0)
{
foreach(集合中的变量i)
{
Console.WriteLine(“它们是:”+i);
x++;
如果(x==100)
{
打破
}
}
}
}
});
Console.ReadKey();

请注意,如果使用ConcurrentBag替换SynchronizedCollection,您将获得线程安全性:

var collection = new ConcurrentBag<int>();
var collection=new ConcurrentBag();

SynchronizedCollection在此应用程序中不是线程安全的。请改用并发集合。

正如Alexander已经指出的,
SynchronizedCollection
在这种情况下不是线程安全的。
SynchronizedCollection
实际上包装了一个普通的泛型列表,只需将每个调用委托给底层列表,并在调用周围加上一个锁。这也可以在
GetEnumerator
中完成。因此,枚举数的获取是同步的,而不是实际的枚举

var collection = new SynchronizedCollection<string>();
collection.Add("Test1");
collection.Add("Test2");
collection.Add("Test3");
collection.Add("Test4");

var enumerator = collection.GetEnumerator();
enumerator.MoveNext();
collection.Add("Test5");
//The next call will throw a InvalidOperationException ("Collection was modified")
enumerator.MoveNext();
var collection=newsynchronizedcollection();
集合。添加(“测试1”);
集合。添加(“测试2”);
集合。添加(“测试3”);
集合。添加(“测试4”);
var枚举器=collection.GetEnumerator();
枚举数。MoveNext();
集合。添加(“测试5”);
//下一个调用将抛出InvalidOperationException(“集合已修改”)
枚举数。MoveNext();
使用foreach时,将以这种方式调用枚举数。因此,在通过该数组枚举之前添加
ToArray()
也不会起作用,因为这将首先枚举到此数组中。 当您在foreach中执行的操作时,此枚举可能会更快,因此它可以降低出现并发问题的概率。
正如Richard指出的:为了真正的线程安全,请使用
系统.Collections.Concurrent
类。

如果您使用的是SynchronizedCollection,它应该已经为添加/从集合中删除的操作提供了适当的锁定。这是否也支持在从不同线程删除项时在另一个线程中枚举集合?我是否需要锁定枚举部分?现有“SynchronizedCollection”的全部要点是为所有操作提供线程安全的集合(它通过
锁定所有操作来实现)。如果您使用的是ICollection中的内容,那么您可能需要自己锁定。请注意,如果您的目标是4.0 framework或更高版本,您可能会在使用System.Collections.Concurrent时看到性能的改进……同步收集对于多个读卡器和一个写入器是否是线程安全的?我认为这取决于使用收集的情况。例如:如果您试图通过特定值(例如属性值大于20的项)在集合中查找项,并更改该项,则您没有原子操作,但需要锁定IEnumerable扩展方法不安全(如Max()、Min()等)。如果在多线程环境中执行,则使用这些扩展方法会对您造成不利影响。但是,您可以在调用
ToArray
之前使用集合的
SyncRoot
属性。