C# with Monitor Collection was modified; enumeration operation might not execute

0

I am performing a simple operation of getting a Column from DataTable. After performing this operation in Threaded environment, I am facing exception. However, I added Monitors to keep a check on the object. I still get the exception.

Exception: InvalidOperationException: Collection was modified; enumeration operation might not execute.

Error at Line : Items = result.AsEnumerable().AsParallel().Select(y => y.Field(ExtractField)).ToList();

Code Snippet:

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;

        }

Exception in detail:

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)

Please help here.

c#
multithreading
linq
concurrency
asked on Stack Overflow Feb 26, 2019 by Mohit Kanojia

1 Answer

0

You can block other threads from modifying the collection by implementing a lock. This will essentially make the method synchronous.

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;
}
answered on Stack Overflow Feb 26, 2019 by mr.coffee

User contributions licensed under CC BY-SA 3.0