A number of customers have asked about the threading model used for WF 4. In brief, our extensibility for threading in the WF Runtime is based on System.Threading.SynchronizationContext.
When a execution is kicked off (indirectly through ActivityRuntime.Run), we will first call SynchronizationContext.OperationStarted(). Next we will call SynchronizationContext.Post() to get on a “workflow” thread.
We will then execute any pending work items from our internal scheduler queue. It is possible that more work items will be scheduled (through context.ResumeBookmark, context.ScheduleActivity or activity completion). In that case, we will continue to execute those work items as well. Execution will remain on the “workflow thread” until we either go idle (no more work items), or the runtime is explicitly paused by the host through ActivityRuntime.RequestPause (which is what’s called underneath Unload() for example). When this happens, we will call SynchronizationContext.OperationCompleted().
How you configure a SynchronizationContext depends on the host construct that you are using.
- For WorkflowServiceHost, we will use the the value of SynchronizationContext.Current at the time of workflowServiceHost.Open (unless UseSynchronizationContext is set to false). This is consistent with the rest of WCF.
- WorkflowInvoker.Invoke/BeginInvoke has overloads where you can explicitly provide a SynchronizationContext for us to use
- WorkflowInvoker.InvokeAsync will use the value of SynchronizationContext.Current for consistency with the Whidbey async pattern
- WorkflowInstance has a constructor overload which allows you to explicitly provide a SynchronizationContext for us to use
If no SynchronizationContext is provided by the host, we will use an internal WF default SynchronizationContext. The WF default SynchronizationContext uses IO completion ports under the hood to implement Post().