Partilhar via


CCR tips and tricks - part 24

Today I'll show you an example of how can use the pattern used in part 23 to make the utilities from part 1 look a little different and also work for any number of branches in a choice. But there is an important consequence of this.

   1: public static void CompleteSynchronously(this Choice choice)
  2: {
  3:     var choiceCompletedPort = new Port<EmptyValue>();
  4:     Arbiter.Activate(
  5:         taskQueue,
  6:         Arbiter.FromIteratorHandler(
  7:             () => ExecuteChoice(choice, choiceCompletedPort)));
  8:     using (var mre = new ManualResetEvent(false))
  9:     {
 10:         Arbiter.Activate(
 11:             taskQueue, 
 12:             choiceCompletedPort.Receive(_ => mre.Set()));
 13:         mre.WaitOne();
 14:     }
 15: }

While this looks neat there is a problem with this implementation that was covered in part 7. There is a race condition in that when the choice completes it has only scheduled the choice handler for execution. So ExecuteChoice may post to its completion port which means that the handler that sets the event is also scheduled for execution. Hence we have two handlers scheduled for execution and we do not know which once will execute first nor will be know if the WaitOne (line 13) will be released before the choice handler completes. So this solution does not work well if you need 100% guarantee that the choice handler has executed when CompleteSynchronously returns but this method works if you want something that waits until the choice is resolved and a handler scheduled.