具有Monitor Collection的C#已被修改;枚举操作可能无法执行

时间:2019-02-26 00:08:05

标签: c# multithreading linq concurrency

我正在执行从DataTable获取列的简单操作。在线程环境中执行此操作后,我面临异常。但是,我添加了Monitors来保持对对象的检查。我仍然有例外。

异常:InvalidOperationException:集合已修改;枚举操作可能无法执行。

在线错误:项目= result.AsEnumerable()。AsParallel()。Select(y => y.Field(ExtractField))。ToList();

代码段:

private List<string> SomeMethod(string ExtractField)
        {

            List<string> Items = null;

            if (Monitor.TryEnter(_locker, 100))
            {
                try
                {
                    DataTable result = GetDataTable();

                    if (Monitor.TryEnter(_locker1, 100))
                    {
                        try
                        {
                            Items = result.AsEnumerable().AsParallel().Select(y => y.Field<string>(ExtractField)).ToList(); // ExtractFeild is the column Name
                        }

                        finally
                        {
                            Monitor.Exit(_locker1);
                        }
                    }

                    Items.RemoveAll(item => String.IsNullOrEmpty(item));
                    return Items;
                }
                finally
                {
                    Monitor.Exit(_locker);
                }

            }

            return Items;

        }

详细的异常:

System.AggregateException
  HResult=0x80131500
  Message=One or more errors occurred.
  Source=System.Core
  StackTrace:
   at System.Linq.Parallel.QueryTaskGroupState.QueryEnd(Boolean userInitiatedDispose)
   at System.Linq.Parallel.DefaultMergeHelper`2.System.Linq.Parallel.IMergeHelper<TInputOutput>.Execute()
   at System.Linq.Parallel.MergeExecutor`1.Execute[TKey](PartitionedStream`2 partitions, Boolean ignoreOutput, ParallelMergeOptions options, TaskScheduler taskScheduler, Boolean isOrdered, CancellationState cancellationState, Int32 queryId)
   at System.Linq.Parallel.PartitionedStreamMerger`1.Receive[TKey](PartitionedStream`2 partitionedStream)
   at System.Linq.Parallel.UnaryQueryOperator`2.UnaryQueryOperatorResults.ChildResultsRecipient.Receive[TKey](PartitionedStream`2 inputStream)
   at System.Linq.Parallel.ScanQueryOperator`1.ScanEnumerableQueryOperatorResults.GivePartitionedStream(IPartitionedStreamRecipient`1 recipient)
   at System.Linq.Parallel.UnaryQueryOperator`2.UnaryQueryOperatorResults.GivePartitionedStream(IPartitionedStreamRecipient`1 recipient)
   at System.Linq.Parallel.QueryOperator`1.GetOpenedEnumerator(Nullable`1 mergeOptions, Boolean suppressOrder, Boolean forEffect, QuerySettings querySettings)
   at System.Linq.Parallel.QueryOpeningEnumerator`1.OpenQuery()
   at System.Linq.Parallel.QueryOpeningEnumerator`1.MoveNext()
   at System.Linq.ParallelEnumerable.ToList[TSource](ParallelQuery`1 source)

请在这里帮助。

1 个答案:

答案 0 :(得分:0)

您可以通过实现锁来阻止其他线程修改集合。这实际上将使方法同步。

private static object _lock = new object();

private List<string> SomeMethod(string ExtractField)
{
    List<string> Items = null;
    try
    {
        lock (_lock)
        {       
            DataTable result = GetDataTable();
            Items = result.AsEnumerable().AsParallel().Select(y => y.Field<string>(ExtractField)).ToList();
            Items.RemoveAll(item => String.IsNullOrEmpty(item));            
        }
    }
    catch (Exception ex)
    {
        // ...
    }
    return Items;
}