Describe the issue:
The PreviewForm's refresh action includes updating the animations, models, and textures list. It does so by enumerating through the AllAnimations, AllEntities and AllTextures lists that are stored in Program. The problem is that these lists can be modified by the parallel scan threads while PreviewForm is enumerating through them, causing an InvalidOperationException because the list was modified, thus invalidating the enumeration process.
It looks like the code causing this is Parallel.ForEach used for ProcessFile. There's no other situation that could cause this issue, since ReloadItems is only called by the scan thread after an item is added. But if multiple scan threads are running then this can absolutely happen.
Solution:
Locking can be used on the list object when adding to each individual list, and when updating/refreshing each individual list. That way only one thread will have access to the list until it's done using it.
Ideally, Add* functions should added to Program to automatically handle the locking.
Describe the issue: The
PreviewForm
's refresh action includes updating the animations, models, and textures list. It does so by enumerating through theAllAnimations
,AllEntities
andAllTextures
lists that are stored inProgram
. The problem is that these lists can be modified by the parallel scan threads whilePreviewForm
is enumerating through them, causing anInvalidOperationException
because the list was modified, thus invalidating the enumeration process.It looks like the code causing this is
Parallel.ForEach
used forProcessFile
. There's no other situation that could cause this issue, sinceReloadItems
is only called by the scan thread after an item is added. But if multiple scan threads are running then this can absolutely happen.Callstack: UI Thread:
PreviewForm.UpdateRootEntities(List)
DoScan.AnonymousMethod(PreviewForm)
(refreshAction)PreviewForm.ReloadItems()
Scan Thread:
PreviewForm.ReloadItems()
Program.ScanFiles.AnonymousMethod(RootEntity, long)
Classes.CrocModelReader.LookForCrocModel(BinaryReader, string)
Program.ScanFiles.AnonymousMethod(BinaryReader, string)
Program.ProcessFile(Stream, string, Action)
Program.ProcessFiles.AnonymousMethod(Action)
Solution: Locking can be used on the list object when adding to each individual list, and when updating/refreshing each individual list. That way only one thread will have access to the list until it's done using it.
Ideally,
Add*
functions should added toProgram
to automatically handle the locking.