I have a scene graph of a tree structure in my own game.
The parent node has multiple child nodes, and as the game progresses, nodes are added or deleted.Hello is a change to the collection.Asynchronous programming using async/wait may cause an exception, depending on the timing, to change the collection from another thread while spinning in
The question is, what is the best way to operate the collection with asynchronous programming?
I can't decide whether it's right or wrong.Please let me know what you think.
Add considering your answers
4. includes ConcurrentBag, ConcurrentStack, ConcurrentQueue, ConcurrentDictionary, etc.The call method is significantly different than the existing list.The Producer-Consumer pattern is based on queues and stacks.
5. is a library provided by Microsoft that is not a .Net standard.Installable with NuGet.It's an immutable collection, so there's no problem in a multi-threaded environment.Collection changes are relatively expensive because they are copied and replaced with changes.There is no problem with just browsing.
The ImmutableList number 5 is the best, considering that exclusive control does not appear in the code, that it has an interface similar to the existing list, and that rewriting is negligible because it does not occur that often.
It's not a .Net standard at the moment, but I think it's going to be incorporated as a standard.This is convenient.
Use the System.Collections.Concurrent namespace collection.
Collections belonging to this namespace are asynchronously accessible simultaneously.
There is no need to lock.
Another way to do this is to
attribute to the System.Collections.Impossible namespace. Use an invariant collection.
Changes to a collection of invariant collections create references to the new collection.
System.Collections.Impossible may not be available as a standard.
It can be deployed via nuget.
These collections allow you to program lock-free.
Changing a collection during an enumeration operation does not result in an exception.
If Read > Write frequency to the collection is Read > Write, then
You may want to consider using .
However, since the overhead is larger than that of a typical Monitor Lock, for example, a Wirte>Read frequency can be more efficient.
I would like to add that the priority is often considered.
The answer is based on the assumption that the tree structure scene graph (hereinafter referred to as the tree) must be consistent.
If not, I think it is sufficient to use the System.Collections.Concurrent or System.Collections.Impossible collection (hereinafter referred to as the lock-free collection).
Normally, you cannot use the lock statement freely if you use the async/away pattern, but one solution is to use using.
Select here if you want to use ReaderWriterLock.
Building Async Coordination Primitives, Part 7: AsyncReaderWriterLock
Any operation can be atomic, so the tree structure can be consistent at all times.
Even if you have multiple update threads, you can keep them consistent as long as they are locked correctly.
AsyncLock is the same as SemaphoeSlim and is not designed to be re-entered.
In the example code above, if you call LockAsync within the FooAsync method, it will be dead-locked.
Less smart ingenuity is required, such as having a lock argument or being careful not to lock only certain methods.
Prepare two trees: an update tree and a read tree.
The foreach reader looks at the snapshot tree.
You update the tree against the update tree.
When the update is complete, clone the entire update tree and use the Interlocked.Exchange method to replace the copied tree with the read tree.
Allows consistency of the read tree structure.
You don't need to lock, so you don't have to worry about deadlock.
If the tree has a large number of nodes, it consumes a large amount of memory, and the clone operation is a burden to the CPU.
Also, if you have multiple update threads and update them at the same time, and the update tree remains inconsistent after all of these updates have been completed, the read tree that you copied will also become inconsistent.
For example, if a node swap operation is performed asynchronously while reading a tree, the node appears to the reader to suddenly disappear or the same node appears twice.
Think of it as something similar to the Phantom Read phenomenon in RDB.
Another example is to add new N nodes as children of different parent nodes at the same time.
This operation cannot be atomic in the lock-free collection.
It does not appear to the reader to have been "added at the same time."
If you don't have game logic for this situation, you'll find it very difficult to debug because it's not reproducible and confusing bugs and looks bad.
If I were you, I'd look like this
© 2022 OneMinuteCode. All rights reserved.