Crumblenautjs
Crumblenautjs

Reputation: 169

Collection was modified after the enumerator was instantiated error

I'm trying to print multiple PDF byte arrays. Since I need the functionality to allow users to be able to print multiple reports simultaneously, I'm using a Parallel foreach. The function gets through the first byte array fine, but on the second Dequeue I get the "Collection was modified after the enumerator was instantiated." error. How do I fix this while still allowing the users to print simultaneously?

Here's the code:

public static void PrintingQueue(Queue<byte[]> printQueue, string printer, int copies)
    {
        Parallel.ForEach(printQueue, (currentFile) =>
        {
            var printFile = printQueue.Dequeue();
            PrintWithGSPrint(printFile, printer, copies);

        });
    }

Upvotes: 3

Views: 22808

Answers (4)

Fiad
Fiad

Reputation: 803

you are trying to modify the printQueue (by calling Dequeue) within the context of a Parallel.ForEach loop. This is not safe, as it leads to concurrent modification of the collection, which is not allowed.

Try this:

public static void PrintingQueue(Queue<byte[]> printQueue, string printer, int copies)
{
    List<Task> printTasks = new List<Task>();

    while (printQueue.Count > 0)
    {
        byte[] currentFile = printQueue.Dequeue();
        Task printTask = Task.Run(() => PrintWithGSPrint(currentFile, printer, copies));
        printTasks.Add(printTask);
    }

    Task.WhenAll(printTasks).Wait();
}

public static void PrintWithGSPrint(byte[] file, string printer, int copies)
{
    // Your print logic goes here
}

Upvotes: 0

ivan chu
ivan chu

Reputation: 1

In my experience, just add List.Clear() after the looping that should fix your issue.

printQueue.Clear();

Upvotes: 0

Jon
Jon

Reputation: 3255

Try this solution:

The Parallel.ForEach method gives you a parameter for each item in the queue. Use that parameter in the method to do the print. Then just clear the queue when you're done.

public static void PrintingQueue(Queue<byte[]> printQueue, string printer, int copies)
{
    Parallel.ForEach(printQueue, (currentFile) =>
    {
        PrintWithGSPrint(currentFile, printer, copies);
    });

    printQueue.Clear();
}

Upvotes: 1

NicoRiff
NicoRiff

Reputation: 4883

The exception is telling you what is happening. As the collection is being modified, the foreach statement cannot execute correctly. With the Dequeue method, you are removing an item from the collection in which you are iterating. Do not remove the item inside the foreach loop, just clean the collection when you have finished your task.

https://msdn.microsoft.com/en-us/library/1c8bzx97(v=vs.110).aspx

Another thing you can do, is iterate through your collection backwards using a for statement. That way you will be able to remove the elements if it is a must. You can use this answer to see how to iterate backwards: https://stackoverflow.com/a/1582317/637840

Upvotes: 7

Related Questions