locked
Concurrency issues

    Question

  • If you run the example you will notice that the program deadlocks at WaitHandle.WaitAll().  Uncomment "//Program.mres[workflowNumber].WaitOne();" and the program doesn't deadlock anymore.  But, I don't want to WaitOne.  I want all the workflows to run in parallel.

     I discovered that without "Program.mres[workflowNumber.WaitOne();", the WorkflowCompleted event never fires.  I am clueless as to why this is.

    using System;
    using System.Threading;
    using System.Workflow.Runtime;
    using System.IO;
    
    namespace WorkflowConsoleApplication1
    {
     class Program
     {
      public static ManualResetEvent[] mres;
      int numberofWorkflowsToLaunch;
    
      public Program()
      {
       numberofWorkflowsToLaunch = 5;
       mres = new ManualResetEvent[numberofWorkflowsToLaunch];
       for (int i = 0; i < numberofWorkflowsToLaunch; i++)
        mres[i] = new ManualResetEvent(false);
      }
      static void Main(string[] args)
      {
       Program p = new Program();
       FileStream fs = new FileStream(@"C:\Share\output.txt", FileMode.Truncate);//reset log
       fs.Close();
    
       WorkflowController wfc = new WorkflowController();
       for (int i = 0; i < p.numberofWorkflowsToLaunch; i++)
       {
        wfc.CreateWorkflowOne(i);
       }
       WaitHandle.WaitAll(mres);
      }
     }
     internal class WorkflowController
     {
      public static object lockObj = new object();
    
      internal WorkflowController()
      {
    
      }
      internal void CreateWorkflowOne(int workflowNumber)
      {
       using (WorkflowRuntime workflowRuntime = new WorkflowRuntime())
       {
        workflowRuntime.WorkflowCompleted += delegate(object sender, WorkflowCompletedEventArgs e) 
        {
         Program.mres[workflowNumber].Set();
        };
        workflowRuntime.WorkflowTerminated += delegate(object sender, WorkflowTerminatedEventArgs e)
        {
         Console.WriteLine(e.Exception.Message);
         Program.mres[workflowNumber].Set();
        };
    
        WorkflowInstance instance = workflowRuntime.CreateWorkflow(typeof(WorkflowConsoleApplication1.Workflow1));
        instance.Start();
    
        //Program.mres[workflowNumber].WaitOne();
       }
      }
     }
    }
    
    
    Workflow code
    
     public sealed partial class Workflow1 : SequentialWorkflowActivity
     {  
      public Workflow1()
      {
       InitializeComponent();
      }
    
      private void codeActivity1_ExecuteCode(object sender, EventArgs e)
      {
       lock (WorkflowController.lockObj)
       {
        FileStream fs = new FileStream(@"C:\Share\output.txt", FileMode.Append);
        StreamWriter sw = new StreamWriter(fs);
        sw.WriteLine("Hello World");
        Thread.Sleep(1000);
        sw.Close();
       }
      }
     }
    

    BrianMackey.NET
    Thursday, May 13, 2010 6:24 PM

Answers

  • The problem is not with the implementation but with your understanding of that implementation. The way WF 3.5 works under the hood is that it similates parallell processing in the same way a single processing computer does. The WF Runtime has an internal scheduler queue that is single threaded and as your activities create items to be placed on the queue they execute in a sequential fashion. Your WF's all contain only one activity and these activities incorrectly don't return immediately as they should. This makes it not possible to have psuedo parallel processing because your not putting more than one item on the queue for each WF instance. 

    Alos, the WF paridigm calls for executing quickly and returning control. If you have a long running activity then it should be delegated to an external component so that you don't block the scheduler or you can do things like using bookmarks to continue execution if your activity needs to wait. You are making the problem worst by breaking this best practice for using WF.

    I'd strongly recomend you read Essential Windows Workflow Foundation to get a better understanding of how things work in WF and to better understand these issues that are confusing you. It's a complicated architecture and does require some time spent learning it even for experienced programmers. Basically, you have to read the manual with WF before you can be effective.

    http://www.amazon.com/Essential-Windows-Workflow-Foundation-Dharma/dp/0321399838

     


    If my response answers your question, please mark it as the "Answer" by clicking that button above my post.

    My blog: http://www.RyanVice.net/
    Friday, May 14, 2010 3:48 PM
    Moderator
  • http://msdn.microsoft.com/en-us/library/aa349443(v=VS.90).aspx

    You can also write your own scheduler if you want to have different behavior but I wouldn't recomend it. Best bet is to give that book I posted a quick read, learn the paradigm and see if the recomended approach works.

    Good luck Brian


    If my response answers your question, please mark it as the "Answer" by clicking that button above my post.

    My blog: http://www.RyanVice.net/
    Friday, May 14, 2010 6:42 PM
    Moderator

All replies

  • For some reason if I comment out or set Thread.Sleep to a very low value like 1 the event fires again.  As you can see, this example is very basic.  All I do is write "hello world" to a text file.  There appears to be something wrong with the Workflow implementation code.  It does not allow workflows to run in parallel.
    BrianMackey.NET
    Friday, May 14, 2010 3:17 AM
  • The problem is not with the implementation but with your understanding of that implementation. The way WF 3.5 works under the hood is that it similates parallell processing in the same way a single processing computer does. The WF Runtime has an internal scheduler queue that is single threaded and as your activities create items to be placed on the queue they execute in a sequential fashion. Your WF's all contain only one activity and these activities incorrectly don't return immediately as they should. This makes it not possible to have psuedo parallel processing because your not putting more than one item on the queue for each WF instance. 

    Alos, the WF paridigm calls for executing quickly and returning control. If you have a long running activity then it should be delegated to an external component so that you don't block the scheduler or you can do things like using bookmarks to continue execution if your activity needs to wait. You are making the problem worst by breaking this best practice for using WF.

    I'd strongly recomend you read Essential Windows Workflow Foundation to get a better understanding of how things work in WF and to better understand these issues that are confusing you. It's a complicated architecture and does require some time spent learning it even for experienced programmers. Basically, you have to read the manual with WF before you can be effective.

    http://www.amazon.com/Essential-Windows-Workflow-Foundation-Dharma/dp/0321399838

     


    If my response answers your question, please mark it as the "Answer" by clicking that button above my post.

    My blog: http://www.RyanVice.net/
    Friday, May 14, 2010 3:48 PM
    Moderator
  • I get the gist of what your saying, but to fully understand it I believe I'll need to read the manual as you suggest.

    Thanks Ryan, that is an excellent answer. 


    BrianMackey.NET
    Friday, May 14, 2010 4:34 PM
  • Ryan, I need to find some references to backup what you are telling me in order to show my superior.  Do you have any online references for the "sequential fashion" and/or the "calls for executing quickly and returning control"?  Something covering the WF runtime would be great as well.
    BrianMackey.NET
    Friday, May 14, 2010 5:35 PM
  • http://msdn.microsoft.com/en-us/library/aa349443(v=VS.90).aspx

    You can also write your own scheduler if you want to have different behavior but I wouldn't recomend it. Best bet is to give that book I posted a quick read, learn the paradigm and see if the recomended approach works.

    Good luck Brian


    If my response answers your question, please mark it as the "Answer" by clicking that button above my post.

    My blog: http://www.RyanVice.net/
    Friday, May 14, 2010 6:42 PM
    Moderator