Thread communication

I am trying to solve a minor curiousity and despite reading several threading sources i simply do not -understand- how to do it.

I have a class A. Class A is created when the MainForm is created. Fine.

Class A also contains a public event OnData delegate to pass data from class A to the mainform. This also works fine. I get thread synchronization problems when introducing a thread to do my data reading.

I introduced into class A a void ReadMyData, a threaded function. This function, whenever it detects data, should call the OnData delegate event. I can perfectly understand why why calling OnData from the ReadMyData goes wrong: my created thread is not synchronized to the thread the remainder of class A is running.

To this end, I must somehow call the OnData event from the same thread as the remainder of the class is running:the GUI thread. Moreso, because I do not want to be dependant on forms AND want to hide the thread from external trouble, I cannot do the invoke trick from the delegate implementation on the form side.

Does anyone understand what I'm trying to do I'll give a short example of my class A. The class is created from the mainform & the even Test is implemented to update a GUI component.



public delegate void Test ( string t );

public class ThreadTest

{

   private Thread t;

   public event Test test;

   public void ThreadProcess()

   {

      while (1 == 1)

      {

         Thread.Sleep(1000);

         if (test != null) test.Invoke("test");

      }

   }

   public void Start()

   {

      t = new Thread ( new ThreadStart(ThreadProcess) );

      t.Start();

   }

}


 


Answer this question

Thread communication

  • TDeveloper

    [Begin]Invoke() is a means by which to transfer process control, not synchronization.

    Your original message suggested you were looking for a way to ensure form-accesing routines where called from the GUI thread.

    Let's forget delegates and events for this topic.  With multi-threaded programming you have to deal with synchronization.  With Windows you also have to deal with ensuring that only the GUI thread accesses windows' controls.  This requirement means you simply cannot share control variables (either globally or via public members) and expect to guarentee this.

    Synchronization is used so only one thread at a time accesses shared data/resources (global/public variables, handles, etc.).  The Monitor pattern is used in .NET to accomplish this.

    To ensure the GUI thread is the only thread accessing control's directly a non-GUI thread can transfer process control either synchronously (blocking) or asynchronously (non-blocking) by calling the control's Invoke() and BeginInvoke() methods respectively.  This can be done either outside of the control class code or within the control class code.  My preference is to decouple this and keep it within the control class code, as per my pervious  examples.  If you ensure all control members are guarded this way then there's no need to deal with synchronization with control class members--only one thread is going to access them.

    Are you unclear on something other than these two subjects



  • Afsoon

    True. I was aware of this method.

    However, I am trying to hide the invoke complexity in the implemented delegates inside the form. Basically, whoever uses Class A shouldn't have to worry about invoke's because the thread Class A creates internally should be hidden.

    This means that if possible I'd like to be untied to the form implementation, instead insuring that somehow the thread which is created by Class A synchronizes itself with the GUI thread -before- calling the event delegate in class A. Which means we'd have to somehow synchronize the thread with the thread on which class A was originally created. (possibly the gui thread).

  • Alon *

    Mmm...that's another way of looking at it.

    I suppose you're saying for threads communicating with threads, simply use monitors or critical sections and for the GUI thread use the invoke for means as synchronizing

  • MartinY

    You would have to couple class A to the Form class to do this.  You can't "inject" code into another thread.  You can send a message to a form to be processed by that form, on it's main thread.  This is done with the Form.BeginInvoke() method.

    Why would anything other than the Form care what thread it's running on   Why have multiple threads if you want everything to run on the main GUI thread   The method I presented previously reduces coupling by keeping implementation details and dependancies to where they occur--the Form class.  Only it should know whether something should be Invoke'd or not.  An outside class should simply call a method--why should it be coupled to Form.InvokeRequired



  • rpark68

    Unless class A is accessing any controls, you shouldn't have a problem.  If class A is accessing a Form object, then all accesses should be done through a method of property so you can make then thread-safe.

    A form method/property can be made thread safe by invoking a delegate after checking the form's InvokeRequired property.  This is most easily done with events and callbacks becuase a delegate is already defined; but, you can always define your own.

    For example, if you had an event handler on a Form class called through the delegate "MyDelegate" you would ensure control access is performed on the GUI thread as follows:

    public OnGo(string text)
    {
        if(this.InvokeRequired)
        {
            this.BeginInvoke(new MyDelegate(OnGo), new object[] {text});
        }
        else
        {
            // TODO: handle event thread-safely.
        }
    }

    If you are calling into a Form-deriived class from class A, then the method on the Form-derived class has do the same thing; but, you have to create a delegate to match the method.  For example:

    public class MyForm : System.Windows.Forms.Form
    {
    // ...
        private delegate void FromClassADelegate(string text);
        public void FromClassA(string text)
        {
            if(this.InvokeRequired)
            {
                this.BeginInvoke(new FromClassADelgate(FromClassA), new object[] {text});
            }
           else
           {
               // TODO: thread-safe code here.
           }
        }
    }

    In the above example, it's all done by the MyForm class so class A (or whomever calls FromClassA() ) isn't coupled to MyForm's implementation.

    http://www.peterRitchie.com/



  • Thread communication