Search code examples
c#json.nettaskjsonserializer

How to avoid collection modification during JSON serialization in looped multithreaded task?


I have a problem during serialization to JSON file, when using Newtonsoft.Json.

In a loop I am fiering tasks in various threads:

List<Task> jockeysTasks = new List<Task>();

            for (int i = 1; i < 1100; i++)
            {
                int j = i;
                Task task = Task.Run(async () =>
                {
                    LoadedJockey jockey = new LoadedJockey();
                    jockey = await Task.Run(() => _scrapServices.ScrapSingleJockeyPL(j));

                    if (jockey.Name != null)
                    {
                        _allJockeys.Add(jockey);
                    }

                    UpdateStatusBar = j * 100 / 1100;

                    if (j % 100 == 0)
                    {
                        await Task.Run(() => _dataServices.SaveAllJockeys(_allJockeys)); //saves everything to JSON file
                    }
                });

                jockeysTasks.Add(task);
            }

            await Task.WhenAll(jockeysTasks);

And if (j % 100 == 0), it is rying to save the collection _allJockeys to the file (I will make some counter to make it more reliable, but that is not the point):

public void SaveAllJockeys(List<LoadedJockey> allJockeys)
        {
            if (allJockeys.Count != 0)
            {
                if (File.Exists(_jockeysFileName)) File.Delete(_jockeysFileName);

                try
                {
                    using (StreamWriter file = File.CreateText(_jockeysFileName))
                    {
                        JsonSerializer serializer = new JsonSerializer();
                        serializer.Serialize(file, allJockeys);
                    }
                }
                catch (Exception e)
                {
                    dialog.ShowDialog("Could not save the results, " + e.ToString(), "Error");
                }
            }
        }

During that time, as I belive, another tasks are adding new collection item to the collection, and it is throwing to me the exception:

Collection was modified; enumeration operation may not execute.

As I was reading in THE ARTICLE, you can change type of iteration to avoid an exception. As far as I know, I can not modify the way, how Newtonsoft.Json pack is doing it.

Thank you in advance for any tips how to avoid the exception and save the collection wihout unexpected changes.


Solution

  • I tied to use ToList() on the collection, what creates copy of the list, with positive effect.