.net - How to handle many concurrently interacting entities in C# -


i developing application has many different entities can interact concurrently. i'm wondering best way entities interact each other in thread safe way.

to demonstrate simplified code, consider each entity has it's own fiber , state:

class fiber {     private actionblock<action> _workqueue;      public fiber()     {         _workqueue = new actionblock<action>((a) => a());     }      public void enqueue(action a)     {         _workqueue.post(a);     }      public void stop()     {         _workqueue.complete();     } }  class entitystate {     public int x { get; set; } }  class entity {     private fiber _fiber = new fiber();      public entitystate state { get; set; }      // ... } 

assume actions arbitrarily enqueued onto entities fiber. 1 such action may entity must modify entity's state. there 2 options i've considered in thread safe way.

option 1: allow state mutation through thread-safe wrapper, i.e.

class entity {     private fiber _fiber = new fiber();      private readerwriterlockslim _statelock = new readerwriterlockslim();     private entitystate _state = new entitystate();      public t readstate<t>(func<entitystate, t> reader)     {         t result = default(t);          _statelock.enterreadlock();         result = reader(_state);         _statelock.exitreadlock();          return result;     }      public void writestate(action<entitystate> writer)     {         _statelock.enterwritelock();         writer(_state);         _statelock.exitwritelock();     }      // ... } 

option 2: allow state mutation scheduling onto owning entity's fiber , return future mutator can see when mutation has taken place, i.e.

class future<t> {     public t value { get; set; } }  class entity {     private fiber _fiber = new fiber();      private entitystate _state = new entitystate();      public future<t> accessstate<t>(func<entitystate, t> accessor)     {         future<t> future = new future<t>();          _fiber.enqueue(() => future.value = accessor(_state));          return future;     }      // ... } 

what other options haven't considered? there way this? should doing @ all?

all of options going bring pain you.

  1. even if code technically correct, you'll experience logical race condition in domain. order shipped before paid.
  2. it hurts maintainability. threading code hard debug, hard test, hard read. when it's interleaved application gets more complicated.

the right way separate threading code application code completely. put tasks in single-threaded fiber. task performs jobs synchronously across involved entities. after task finished, can perform io asynchronously. i've written a library such approach.


Comments