GUI Invoke stalls thread

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • k.mellor@iee.org

    GUI Invoke stalls thread

    Hi,

    I hope someone can help. I have written a simple form to demonstrate
    my problem/question. The code follows.

    The form starts a thread, which using delegates updates a label (Every
    second adds another dot to the label). This works great. However,
    when I put the GUI thread to sleep (Thread.Sleep), the thread seems to
    stall. At first I was expecting dots to still appear, but obviously as
    the GUI thread is asleep, they will not. However, the thread never
    hits my break points once the GUI thread is asleep. Am I invoking
    incorrectly? Any help appreciated.

    Kev



    using System;
    using System.Drawing;
    using System.Collecti ons;
    using System.Componen tModel;
    using System.Windows. Forms;
    using System.Data;
    using System.Threadin g;

    namespace WindowsApplicat ion2
    {
    public delegate void MyDelegate();

    public class Form1 : System.Windows. Forms.Form
    {
    private System.Windows. Forms.Label label1;
    private System.Windows. Forms.Button button1;
    private System.Componen tModel.Containe r components = null;

    public Form1()
    {
    InitializeCompo nent();
    }

    private void UpdateLabel()
    {
    if (this.label1.In vokeRequired)
    this.label1.Inv oke(new MyDelegate(this .UpdateLabel));
    else
    this.label1.Tex t += ". ";
    }

    protected override void Dispose( bool disposing )
    {
    if( disposing )
    {
    if (components != null)
    {
    components.Disp ose();
    }
    }
    base.Dispose( disposing );
    }


    #region Windows Form Designer generated code
    /// <summary>
    /// Required method for Designer support - do not modify
    /// the contents of this method with the code editor.
    /// </summary>
    private void InitializeCompo nent()
    {
    this.label1 = new System.Windows. Forms.Label();
    this.button1 = new System.Windows. Forms.Button();
    this.SuspendLay out();
    //
    // label1
    //
    this.label1.Fon t = new System.Drawing. Font("Microsoft Sans
    Serif", 15.75F, System.Drawing. FontStyle.Bold,
    System.Drawing. GraphicsUnit.Po int, ((System.Byte)( 0)));
    this.label1.Loc ation = new System.Drawing. Point(40, 32);
    this.label1.Nam e = "label1";
    this.label1.Siz e = new System.Drawing. Size(232, 96);
    this.label1.Tab Index = 0;
    //
    // button1
    //
    this.button1.Lo cation = new System.Drawing. Point(80, 168);
    this.button1.Na me = "button1";
    this.button1.Si ze = new System.Drawing. Size(96, 32);
    this.button1.Ta bIndex = 1;
    this.button1.Te xt = "button1";
    this.button1.Cl ick += new
    System.EventHan dler(this.butto n1_Click);
    //
    // Form1
    //
    this.AutoScaleB aseSize = new System.Drawing. Size(5, 13);
    this.ClientSize = new System.Drawing. Size(292, 266);
    this.Controls.A dd(this.button1 );
    this.Controls.A dd(this.label1) ;
    this.Name = "Form1";
    this.Text = "Form1";
    this.ResumeLayo ut(false);

    }
    #endregion

    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    [STAThread]
    static void Main()
    {
    Application.Run (new Form1());
    }

    private void button1_Click(o bject sender, System.EventArg s e)
    {
    Worker w = new Worker();
    w.m_delegate = new MyDelegate(this .UpdateLabel);
    Thread t = new Thread(new ThreadStart(w.D oSomething));
    t.Start();
    Thread.Sleep(20 000);
    }


    }

    //
    // work class
    //
    class Worker
    {
    public MyDelegate m_delegate = null;

    public void DoSomething()
    {
    while (true)
    {
    Thread.Sleep(10 00);
    m_delegate();
    }
    }
    }

    } // end of namespace

  • Willy Denoyette [MVP]

    #2
    Re: GUI Invoke stalls thread

    Your "UpdateLabe l" method has to run on the UI thread, but you put your UI
    thread to sleep in your Click handler, that is, you block your UI threa, the
    UpdateLabel method will only execute when the Click handler returns, that is
    after 20 seconds.
    Remove the Sleep call and you are done.

    Willy.


    <k.mellor@iee.o rgwrote in message
    news:1161277501 .371932.199970@ i42g2000cwa.goo glegroups.com.. .
    | Hi,
    |
    | I hope someone can help. I have written a simple form to demonstrate
    | my problem/question. The code follows.
    |
    | The form starts a thread, which using delegates updates a label (Every
    | second adds another dot to the label). This works great. However,
    | when I put the GUI thread to sleep (Thread.Sleep), the thread seems to
    | stall. At first I was expecting dots to still appear, but obviously as
    | the GUI thread is asleep, they will not. However, the thread never
    | hits my break points once the GUI thread is asleep. Am I invoking
    | incorrectly? Any help appreciated.
    |
    | Kev
    |
    |
    |
    | using System;
    | using System.Drawing;
    | using System.Collecti ons;
    | using System.Componen tModel;
    | using System.Windows. Forms;
    | using System.Data;
    | using System.Threadin g;
    |
    | namespace WindowsApplicat ion2
    | {
    | public delegate void MyDelegate();
    |
    | public class Form1 : System.Windows. Forms.Form
    | {
    | private System.Windows. Forms.Label label1;
    | private System.Windows. Forms.Button button1;
    | private System.Componen tModel.Containe r components = null;
    |
    | public Form1()
    | {
    | InitializeCompo nent();
    | }
    |
    | private void UpdateLabel()
    | {
    | if (this.label1.In vokeRequired)
    | this.label1.Inv oke(new MyDelegate(this .UpdateLabel));
    | else
    | this.label1.Tex t += ". ";
    | }
    |
    | protected override void Dispose( bool disposing )
    | {
    | if( disposing )
    | {
    | if (components != null)
    | {
    | components.Disp ose();
    | }
    | }
    | base.Dispose( disposing );
    | }
    |
    |
    | #region Windows Form Designer generated code
    | /// <summary>
    | /// Required method for Designer support - do not modify
    | /// the contents of this method with the code editor.
    | /// </summary>
    | private void InitializeCompo nent()
    | {
    | this.label1 = new System.Windows. Forms.Label();
    | this.button1 = new System.Windows. Forms.Button();
    | this.SuspendLay out();
    | //
    | // label1
    | //
    | this.label1.Fon t = new System.Drawing. Font("Microsoft Sans
    | Serif", 15.75F, System.Drawing. FontStyle.Bold,
    | System.Drawing. GraphicsUnit.Po int, ((System.Byte)( 0)));
    | this.label1.Loc ation = new System.Drawing. Point(40, 32);
    | this.label1.Nam e = "label1";
    | this.label1.Siz e = new System.Drawing. Size(232, 96);
    | this.label1.Tab Index = 0;
    | //
    | // button1
    | //
    | this.button1.Lo cation = new System.Drawing. Point(80, 168);
    | this.button1.Na me = "button1";
    | this.button1.Si ze = new System.Drawing. Size(96, 32);
    | this.button1.Ta bIndex = 1;
    | this.button1.Te xt = "button1";
    | this.button1.Cl ick += new
    | System.EventHan dler(this.butto n1_Click);
    | //
    | // Form1
    | //
    | this.AutoScaleB aseSize = new System.Drawing. Size(5, 13);
    | this.ClientSize = new System.Drawing. Size(292, 266);
    | this.Controls.A dd(this.button1 );
    | this.Controls.A dd(this.label1) ;
    | this.Name = "Form1";
    | this.Text = "Form1";
    | this.ResumeLayo ut(false);
    |
    | }
    | #endregion
    |
    | /// <summary>
    | /// The main entry point for the application.
    | /// </summary>
    | [STAThread]
    | static void Main()
    | {
    | Application.Run (new Form1());
    | }
    |
    | private void button1_Click(o bject sender, System.EventArg s e)
    | {
    | Worker w = new Worker();
    | w.m_delegate = new MyDelegate(this .UpdateLabel);
    | Thread t = new Thread(new ThreadStart(w.D oSomething));
    | t.Start();
    | Thread.Sleep(20 000);
    | }
    |
    |
    | }
    |
    | //
    | // work class
    | //
    | class Worker
    | {
    | public MyDelegate m_delegate = null;
    |
    | public void DoSomething()
    | {
    | while (true)
    | {
    | Thread.Sleep(10 00);
    | m_delegate();
    | }
    | }
    | }
    |
    | } // end of namespace
    |


    Comment

    • k.mellor@iee.org

      #3
      Re: GUI Invoke stalls thread

      Willy,

      many thanks for your reply. I fully understand your answer. Perhpas
      I am not stating the task clearly enough. I have deliberately put the
      GUI thread to sleep to illustrate the problem I want to solve. Evn
      though the GUI thread is alseep, I would still expect the worker thread
      to continue executing.

      So if the GUI thread thread sleeps for 20 seconds, and the worker
      ticks over once a second, I would expect the worker to hit a breakpoint
      (loop) 20 times whilst the GUI is asleep.

      However, the worker thread seems to get blocked. I appreciate that
      whilst the gui is sleeping the label will not get updated, but
      shouldn't the 20 worker thread loops get queued? At the moment the
      worker thread stops, which from my understaning defeats the object of
      test InvokeRequired/Invoke().

      Any thoughts would be helpful.

      Thanks again.
      Willy Denoyette [MVP] wrote:
      Your "UpdateLabe l" method has to run on the UI thread, but you put your UI
      thread to sleep in your Click handler, that is, you block your UI threa, the
      UpdateLabel method will only execute when the Click handler returns, that is
      after 20 seconds.
      Remove the Sleep call and you are done.
      >
      Willy.
      >
      >
      <k.mellor@iee.o rgwrote in message
      news:1161277501 .371932.199970@ i42g2000cwa.goo glegroups.com.. .
      | Hi,
      |
      | I hope someone can help. I have written a simple form to demonstrate
      | my problem/question. The code follows.
      |
      | The form starts a thread, which using delegates updates a label (Every
      | second adds another dot to the label). This works great. However,
      | when I put the GUI thread to sleep (Thread.Sleep), the thread seems to
      | stall. At first I was expecting dots to still appear, but obviously as
      | the GUI thread is asleep, they will not. However, the thread never
      | hits my break points once the GUI thread is asleep. Am I invoking
      | incorrectly? Any help appreciated.
      |
      | Kev
      |
      |
      |
      | using System;
      | using System.Drawing;
      | using System.Collecti ons;
      | using System.Componen tModel;
      | using System.Windows. Forms;
      | using System.Data;
      | using System.Threadin g;
      |
      | namespace WindowsApplicat ion2
      | {
      | public delegate void MyDelegate();
      |
      | public class Form1 : System.Windows. Forms.Form
      | {
      | private System.Windows. Forms.Label label1;
      | private System.Windows. Forms.Button button1;
      | private System.Componen tModel.Containe r components = null;
      |
      | public Form1()
      | {
      | InitializeCompo nent();
      | }
      |
      | private void UpdateLabel()
      | {
      | if (this.label1.In vokeRequired)
      | this.label1.Inv oke(new MyDelegate(this .UpdateLabel));
      | else
      | this.label1.Tex t += ". ";
      | }
      |
      | protected override void Dispose( bool disposing )
      | {
      | if( disposing )
      | {
      | if (components != null)
      | {
      | components.Disp ose();
      | }
      | }
      | base.Dispose( disposing );
      | }
      |
      |
      | #region Windows Form Designer generated code
      | /// <summary>
      | /// Required method for Designer support - do not modify
      | /// the contents of this method with the code editor.
      | /// </summary>
      | private void InitializeCompo nent()
      | {
      | this.label1 = new System.Windows. Forms.Label();
      | this.button1 = new System.Windows. Forms.Button();
      | this.SuspendLay out();
      | //
      | // label1
      | //
      | this.label1.Fon t = new System.Drawing. Font("Microsoft Sans
      | Serif", 15.75F, System.Drawing. FontStyle.Bold,
      | System.Drawing. GraphicsUnit.Po int, ((System.Byte)( 0)));
      | this.label1.Loc ation = new System.Drawing. Point(40, 32);
      | this.label1.Nam e = "label1";
      | this.label1.Siz e = new System.Drawing. Size(232, 96);
      | this.label1.Tab Index = 0;
      | //
      | // button1
      | //
      | this.button1.Lo cation = new System.Drawing. Point(80, 168);
      | this.button1.Na me = "button1";
      | this.button1.Si ze = new System.Drawing. Size(96, 32);
      | this.button1.Ta bIndex = 1;
      | this.button1.Te xt = "button1";
      | this.button1.Cl ick += new
      | System.EventHan dler(this.butto n1_Click);
      | //
      | // Form1
      | //
      | this.AutoScaleB aseSize = new System.Drawing. Size(5, 13);
      | this.ClientSize = new System.Drawing. Size(292, 266);
      | this.Controls.A dd(this.button1 );
      | this.Controls.A dd(this.label1) ;
      | this.Name = "Form1";
      | this.Text = "Form1";
      | this.ResumeLayo ut(false);
      |
      | }
      | #endregion
      |
      | /// <summary>
      | /// The main entry point for the application.
      | /// </summary>
      | [STAThread]
      | static void Main()
      | {
      | Application.Run (new Form1());
      | }
      |
      | private void button1_Click(o bject sender, System.EventArg s e)
      | {
      | Worker w = new Worker();
      | w.m_delegate = new MyDelegate(this .UpdateLabel);
      | Thread t = new Thread(new ThreadStart(w.D oSomething));
      | t.Start();
      | Thread.Sleep(20 000);
      | }
      |
      |
      | }
      |
      | //
      | // work class
      | //
      | class Worker
      | {
      | public MyDelegate m_delegate = null;
      |
      | public void DoSomething()
      | {
      | while (true)
      | {
      | Thread.Sleep(10 00);
      | m_delegate();
      | }
      | }
      | }
      |
      | } // end of namespace
      |

      Comment

      • Willy Denoyette [MVP]

        #4
        Re: GUI Invoke stalls thread


        <k.mellor@iee.o rgwrote in message
        news:1161285858 .088812.121120@ m73g2000cwd.goo glegroups.com.. .
        | Willy,
        |
        | many thanks for your reply. I fully understand your answer. Perhpas
        | I am not stating the task clearly enough. I have deliberately put the
        | GUI thread to sleep to illustrate the problem I want to solve. Evn
        | though the GUI thread is alseep, I would still expect the worker thread
        | to continue executing.
        |
        | So if the GUI thread thread sleeps for 20 seconds, and the worker
        | ticks over once a second, I would expect the worker to hit a breakpoint
        | (loop) 20 times whilst the GUI is asleep.
        |
        | However, the worker thread seems to get blocked. I appreciate that
        | whilst the gui is sleeping the label will not get updated, but
        | shouldn't the 20 worker thread loops get queued?


        No, because you call Invoke, which is synchronous, which means it wait's
        until the posted message (and the associated delegate) has been handled.
        You need to call the asynchronous version BeginInvoke instead.
        Sorry if I wasn't entirely clear in my previous answer.

        Willy.


        Comment

        • k.mellor@iee.org

          #5
          Re: GUI Invoke stalls thread

          I have posted a new code sample below, which is neaer my real world
          problem. I have removed the Thread.Sleep call to remove any
          complications - I am not certain how this affects my previous code.

          The code below has an additional delegate which is called after 10s.
          Every second the label is updated. After 10s a MessageBox is shown on
          screen via InvokeRequired/Invoke().
          The worker thread is programmed to run for 20s and write the numbers 1
          - 20 to the file, closing the file every time.

          However, whilst the message box is on screen the worker thread appears
          to blocked. The numbers 11 - 20 are not written to the file.

          Can anyone help me interpret this behaviour, and get the behaiour I
          desire?

          Thanks all

          using System;
          using System.Drawing;
          using System.Collecti ons;
          using System.Componen tModel;
          using System.Windows. Forms;
          using System.Data;
          using System.Threadin g;
          using System.IO;

          namespace WindowsApplicat ion2
          {
          public delegate void MyDelegate();

          /// <summary>
          /// Summary description for Form1.
          /// </summary>
          public class Form1 : System.Windows. Forms.Form
          {
          private System.Windows. Forms.Label label1;
          private System.Windows. Forms.Button button1;
          private System.Componen tModel.Containe r components = null;

          public Form1()
          {
          InitializeCompo nent();
          }

          private void Form1_Load(obje ct sender, System.EventArg s e)
          {

          }

          private void UpdateLabel()
          {
          if (this.label1.In vokeRequired)
          this.label1.Inv oke(new MyDelegate(this .UpdateLabel));
          else
          this.label1.Tex t += ". ";
          }

          private void ShowMessageBox( )
          {
          if (this.InvokeReq uired)
          this.Invoke(new MyDelegate(this .ShowMessageBox ));
          else
          MessageBox.Show ("Hello");
          }

          protected override void Dispose( bool disposing )
          {
          if( disposing )
          {
          if (components != null)
          {
          components.Disp ose();
          }
          }
          base.Dispose( disposing );
          }


          #region Windows Form Designer generated code
          /// <summary>
          /// Required method for Designer support - do not modify
          /// the contents of this method with the code editor.
          /// </summary>
          private void InitializeCompo nent()
          {
          this.label1 = new System.Windows. Forms.Label();
          this.button1 = new System.Windows. Forms.Button();
          this.SuspendLay out();
          //
          // label1
          //
          this.label1.Fon t = new System.Drawing. Font("Microsoft Sans
          Serif", 15.75F, System.Drawing. FontStyle.Bold,
          System.Drawing. GraphicsUnit.Po int, ((System.Byte)( 0)));
          this.label1.Loc ation = new System.Drawing. Point(40, 32);
          this.label1.Nam e = "label1";
          this.label1.Siz e = new System.Drawing. Size(232, 96);
          this.label1.Tab Index = 0;
          //
          // button1
          //
          this.button1.Lo cation = new System.Drawing. Point(80, 168);
          this.button1.Na me = "button1";
          this.button1.Si ze = new System.Drawing. Size(96, 32);
          this.button1.Ta bIndex = 1;
          this.button1.Te xt = "button1";
          this.button1.Cl ick += new
          System.EventHan dler(this.butto n1_Click);
          //
          // Form1
          //
          this.AutoScaleB aseSize = new System.Drawing. Size(5, 13);
          this.ClientSize = new System.Drawing. Size(292, 266);
          this.Controls.A dd(this.button1 );
          this.Controls.A dd(this.label1) ;
          this.Name = "Form1";
          this.Text = "Form1";
          this.Load += new System.EventHan dler(this.Form1 _Load);
          this.ResumeLayo ut(false);

          }
          #endregion

          /// <summary>
          /// The main entry point for the application.
          /// </summary>
          [STAThread]
          static void Main()
          {
          Application.Run (new Form1());
          }

          private void button1_Click(o bject sender, System.EventArg s e)
          {
          Worker w = new Worker();
          w.m_delegate = new MyDelegate(this .UpdateLabel);
          w.m_delegate2 = new MyDelegate(this .ShowMessageBox );
          Thread t = new Thread(new ThreadStart(w.D oSomething));
          t.Start();
          }


          }

          //
          // work class
          //
          class Worker
          {
          public MyDelegate m_delegate = null;
          public MyDelegate m_delegate2 = null;

          public void DoSomething()
          {
          TextWriter tw = new StreamWriter("C :\\red.txt");
          tw.Close();
          int i = 0;
          while (true)
          {
          tw = new StreamWriter("C :\\red.txt", true);
          i++;
          Thread.Sleep(10 00);
          tw.WriteLine(i) ;
          tw.Close();
          //if (i < 10)
          m_delegate();
          else if (i == 10)
          m_delegate2();
          if (i == 20)
          break;
          }
          tw.Close();
          }
          }

          } // end of namespace

          Comment

          • k.mellor@iee.org

            #6
            Re: GUI Invoke stalls thread

            Willy,

            thnks for your help. Just posted a second ago. You must have
            answered whilst I was composing it. However, using my new sample and
            BEGINinvoke worked perfectly.

            I am about to read more on this, but if you have time and can explain
            it briefly, why would anyone use InvokeRequired/Invoke() like I have if
            Invoke is asynchronous - it blocks the threads stopping my
            multithreaded intention.

            Warmest Regards

            Willy Denoyette [MVP] wrote:
            <k.mellor@iee.o rgwrote in message
            news:1161285858 .088812.121120@ m73g2000cwd.goo glegroups.com.. .
            | Willy,
            |
            | many thanks for your reply. I fully understand your answer. Perhpas
            | I am not stating the task clearly enough. I have deliberately put the
            | GUI thread to sleep to illustrate the problem I want to solve. Evn
            | though the GUI thread is alseep, I would still expect the worker thread
            | to continue executing.
            |
            | So if the GUI thread thread sleeps for 20 seconds, and the worker
            | ticks over once a second, I would expect the worker to hit a breakpoint
            | (loop) 20 times whilst the GUI is asleep.
            |
            | However, the worker thread seems to get blocked. I appreciate that
            | whilst the gui is sleeping the label will not get updated, but
            | shouldn't the 20 worker thread loops get queued?
            >
            >
            No, because you call Invoke, which is synchronous, which means it wait's
            until the posted message (and the associated delegate) has been handled.
            You need to call the asynchronous version BeginInvoke instead.
            Sorry if I wasn't entirely clear in my previous answer.
            >
            Willy.

            Comment

            • k.mellor@iee.org

              #7
              Re: GUI Invoke stalls thread

              Note I referred to Invoke as asynchronous - I meant synchronous. Must
              be coffee time :D

              k.mel...@iee.or g wrote:
              Willy,
              >
              thnks for your help. Just posted a second ago. You must have
              answered whilst I was composing it. However, using my new sample and
              BEGINinvoke worked perfectly.
              >
              I am about to read more on this, but if you have time and can explain
              it briefly, why would anyone use InvokeRequired/Invoke() like I have if
              Invoke is asynchronous - it blocks the threads stopping my
              multithreaded intention.
              >
              Warmest Regards
              >
              Willy Denoyette [MVP] wrote:
              <k.mellor@iee.o rgwrote in message
              news:1161285858 .088812.121120@ m73g2000cwd.goo glegroups.com.. .
              | Willy,
              |
              | many thanks for your reply. I fully understand your answer. Perhpas
              | I am not stating the task clearly enough. I have deliberately put the
              | GUI thread to sleep to illustrate the problem I want to solve. Evn
              | though the GUI thread is alseep, I would still expect the worker thread
              | to continue executing.
              |
              | So if the GUI thread thread sleeps for 20 seconds, and the worker
              | ticks over once a second, I would expect the worker to hit a breakpoint
              | (loop) 20 times whilst the GUI is asleep.
              |
              | However, the worker thread seems to get blocked. I appreciate that
              | whilst the gui is sleeping the label will not get updated, but
              | shouldn't the 20 worker thread loops get queued?


              No, because you call Invoke, which is synchronous, which means it wait's
              until the posted message (and the associated delegate) has been handled.
              You need to call the asynchronous version BeginInvoke instead.
              Sorry if I wasn't entirely clear in my previous answer.

              Willy.

              Comment

              Working...