Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. C#
  4. Usin Invoke with threads

Usin Invoke with threads

Scheduled Pinned Locked Moved C#
designquestion
8 Posts 3 Posters 0 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • P Offline
    P Offline
    polomint
    wrote on last edited by
    #1

    I have a piece of code which runs in another thread (not the UI thread). // listBox1.Items.Add(s); // But because listBox1 was created in another thread, VS2005 does not allow me to do this. I have been told that I need to use BeginInvoke or Invoke on the control to add the item. Does anyone have any ideas on how I would code that? I need to pass a string which will hold the new string to add listBox1. Thanks in advance. John Young Yippee Kai Yai Signed Polomint.......

    N 1 Reply Last reply
    0
    • P polomint

      I have a piece of code which runs in another thread (not the UI thread). // listBox1.Items.Add(s); // But because listBox1 was created in another thread, VS2005 does not allow me to do this. I have been told that I need to use BeginInvoke or Invoke on the control to add the item. Does anyone have any ideas on how I would code that? I need to pass a string which will hold the new string to add listBox1. Thanks in advance. John Young Yippee Kai Yai Signed Polomint.......

      N Offline
      N Offline
      Nick Parker
      wrote on last edited by
      #2

      Something like this should do it:

      using System;
      using System.IO;
      using System.Drawing;
      using System.Windows.Forms;
      using System.Threading;

      class test : System.Windows.Forms.Form
      {

      public delegate void Add(string s);
      public ListBox box;
      public Button button;
      
      public test()
      {
      	InitializeComponents();
      }
      
      public void InitializeComponents()
      {
      	box = new ListBox();
      	button = new Button();
      	button.Location = new Point(70, 120);
      	button.Text = "Click Me";
      	button.Click += new EventHandler(button\_Click);
      	this.Controls.Add(box);
      	this.Controls.Add(button);
      }	
      
      
      private void StringAdder(string s)
      {
      	box.Items.Add(s);
      }
      
      private void button\_Click(object sender, EventArgs e)
      {
      	Thread t = new Thread(new ThreadStart(StartThread));
      	t.Start();
      }
      
      private void StartThread()
      {
      	Add a = new Add(StringAdder);
      	for(int i = 0; i < 100000; i++)
      	{
      		IAsyncResult ar = a.BeginInvoke("Nick", null, null);
      	}
      }
      
      \[STAThread\]
      public static void Main()
      {
      	Application.Run(new test());
      }
      

      }

      - Nick Parker
      My Blog | My Articles

      M 1 Reply Last reply
      0
      • N Nick Parker

        Something like this should do it:

        using System;
        using System.IO;
        using System.Drawing;
        using System.Windows.Forms;
        using System.Threading;

        class test : System.Windows.Forms.Form
        {

        public delegate void Add(string s);
        public ListBox box;
        public Button button;
        
        public test()
        {
        	InitializeComponents();
        }
        
        public void InitializeComponents()
        {
        	box = new ListBox();
        	button = new Button();
        	button.Location = new Point(70, 120);
        	button.Text = "Click Me";
        	button.Click += new EventHandler(button\_Click);
        	this.Controls.Add(box);
        	this.Controls.Add(button);
        }	
        
        
        private void StringAdder(string s)
        {
        	box.Items.Add(s);
        }
        
        private void button\_Click(object sender, EventArgs e)
        {
        	Thread t = new Thread(new ThreadStart(StartThread));
        	t.Start();
        }
        
        private void StartThread()
        {
        	Add a = new Add(StringAdder);
        	for(int i = 0; i < 100000; i++)
        	{
        		IAsyncResult ar = a.BeginInvoke("Nick", null, null);
        	}
        }
        
        \[STAThread\]
        public static void Main()
        {
        	Application.Run(new test());
        }
        

        }

        - Nick Parker
        My Blog | My Articles

        M Offline
        M Offline
        Mike Dimmick
        wrote on last edited by
        #3

        No, that will end up on a thread-pool worker thread. You need to use Control.Invoke (or BeginInvoke) to get back onto the user-interface thread. Control is a placeholder: it's an instance member, so you need to supply a Control or a class derived from Control on the left of .Invoke. The fact that your code sometimes works in .NET 1.x is an accident. There's always a possibility of race conditions or deadlocks. Some controls work, others don't. Typically you'd Invoke on the form itself, e.g.:

        private void StartThread()
        {
        Add a = new Add(StringAdder);
        object[] args = new object[] { "Mike" };

        for(int i = 0; i < 100000; i++)
        {
        this.Invoke( a, args );
        }
        }

        (shamelessly stealing Nick's example). You'd BeginInvoke rather than Invoke if you wanted the UI notification to happen asynchronously. Invoke waits for the UI thread to finish processing the call before continuing. Some sources suggest always using BeginInvoke since you can't know how busy the UI is going to be, and you can end up deadlocking in some situations. This is the equivalent of using PostMessage versus SendMessage in C++ code. Windows Forms 2.0 enforces the correct model: it always throws if you try to update UI from the wrong thread. Stability. What an interesting concept. -- Chris Maunder

        P N 3 Replies Last reply
        0
        • M Mike Dimmick

          No, that will end up on a thread-pool worker thread. You need to use Control.Invoke (or BeginInvoke) to get back onto the user-interface thread. Control is a placeholder: it's an instance member, so you need to supply a Control or a class derived from Control on the left of .Invoke. The fact that your code sometimes works in .NET 1.x is an accident. There's always a possibility of race conditions or deadlocks. Some controls work, others don't. Typically you'd Invoke on the form itself, e.g.:

          private void StartThread()
          {
          Add a = new Add(StringAdder);
          object[] args = new object[] { "Mike" };

          for(int i = 0; i < 100000; i++)
          {
          this.Invoke( a, args );
          }
          }

          (shamelessly stealing Nick's example). You'd BeginInvoke rather than Invoke if you wanted the UI notification to happen asynchronously. Invoke waits for the UI thread to finish processing the call before continuing. Some sources suggest always using BeginInvoke since you can't know how busy the UI is going to be, and you can end up deadlocking in some situations. This is the equivalent of using PostMessage versus SendMessage in C++ code. Windows Forms 2.0 enforces the correct model: it always throws if you try to update UI from the wrong thread. Stability. What an interesting concept. -- Chris Maunder

          P Offline
          P Offline
          polomint
          wrote on last edited by
          #4

          Ok, I understand what you are both saying. Would this work? Also the line Add a = new Add(StringAdder); has me confused. What is add? The compiler complains about me missing a Using directive. string s; s = "Timeout"; Add a = new Add(StringAdder); IAsyncResult ar = a.BeginInvoke(s, null, null); //lbLog.Items.Add(s); Thanks again. PS: What about things like listBox1.Items.Clear() etc... Yippee Kai Yai Signed Polomint.......

          N 1 Reply Last reply
          0
          • M Mike Dimmick

            No, that will end up on a thread-pool worker thread. You need to use Control.Invoke (or BeginInvoke) to get back onto the user-interface thread. Control is a placeholder: it's an instance member, so you need to supply a Control or a class derived from Control on the left of .Invoke. The fact that your code sometimes works in .NET 1.x is an accident. There's always a possibility of race conditions or deadlocks. Some controls work, others don't. Typically you'd Invoke on the form itself, e.g.:

            private void StartThread()
            {
            Add a = new Add(StringAdder);
            object[] args = new object[] { "Mike" };

            for(int i = 0; i < 100000; i++)
            {
            this.Invoke( a, args );
            }
            }

            (shamelessly stealing Nick's example). You'd BeginInvoke rather than Invoke if you wanted the UI notification to happen asynchronously. Invoke waits for the UI thread to finish processing the call before continuing. Some sources suggest always using BeginInvoke since you can't know how busy the UI is going to be, and you can end up deadlocking in some situations. This is the equivalent of using PostMessage versus SendMessage in C++ code. Windows Forms 2.0 enforces the correct model: it always throws if you try to update UI from the wrong thread. Stability. What an interesting concept. -- Chris Maunder

            N Offline
            N Offline
            Nick Parker
            wrote on last edited by
            #5

            Mike Dimmick wrote: Invoke waits for the UI thread to finish processing the call before continuing In my test example, I didn't want to wait, which is why I went with the asynchronous call. Mike Dimmick wrote: Windows Forms 2.0 enforces the correct model: it always throws if you try to update UI from the wrong thread. Hmm, I will have to check this out at home, I don't have Visual Studio 2005 here at work. - Nick Parker
            My Blog | My Articles

            1 Reply Last reply
            0
            • P polomint

              Ok, I understand what you are both saying. Would this work? Also the line Add a = new Add(StringAdder); has me confused. What is add? The compiler complains about me missing a Using directive. string s; s = "Timeout"; Add a = new Add(StringAdder); IAsyncResult ar = a.BeginInvoke(s, null, null); //lbLog.Items.Add(s); Thanks again. PS: What about things like listBox1.Items.Clear() etc... Yippee Kai Yai Signed Polomint.......

              N Offline
              N Offline
              Nick Parker
              wrote on last edited by
              #6

              polomint wrote: What is add? Add was defined as a delegate. You can read more about it here[^]. If you noticed, the StringAdder method I wrote matched the method signature defined in the Add delegate. It basically allows me to treat StringAdder as a callback function when the BeginInvoke method is called from another thread. - Nick Parker
              My Blog | My Articles

              P 1 Reply Last reply
              0
              • N Nick Parker

                polomint wrote: What is add? Add was defined as a delegate. You can read more about it here[^]. If you noticed, the StringAdder method I wrote matched the method signature defined in the Add delegate. It basically allows me to treat StringAdder as a callback function when the BeginInvoke method is called from another thread. - Nick Parker
                My Blog | My Articles

                P Offline
                P Offline
                polomint
                wrote on last edited by
                #7

                Damn, I should have read the code properly. I never noticed the delegate. I've always been impatient. :) Thanks again.. Yippee Kai Yai Signed Polomint.......

                1 Reply Last reply
                0
                • M Mike Dimmick

                  No, that will end up on a thread-pool worker thread. You need to use Control.Invoke (or BeginInvoke) to get back onto the user-interface thread. Control is a placeholder: it's an instance member, so you need to supply a Control or a class derived from Control on the left of .Invoke. The fact that your code sometimes works in .NET 1.x is an accident. There's always a possibility of race conditions or deadlocks. Some controls work, others don't. Typically you'd Invoke on the form itself, e.g.:

                  private void StartThread()
                  {
                  Add a = new Add(StringAdder);
                  object[] args = new object[] { "Mike" };

                  for(int i = 0; i < 100000; i++)
                  {
                  this.Invoke( a, args );
                  }
                  }

                  (shamelessly stealing Nick's example). You'd BeginInvoke rather than Invoke if you wanted the UI notification to happen asynchronously. Invoke waits for the UI thread to finish processing the call before continuing. Some sources suggest always using BeginInvoke since you can't know how busy the UI is going to be, and you can end up deadlocking in some situations. This is the equivalent of using PostMessage versus SendMessage in C++ code. Windows Forms 2.0 enforces the correct model: it always throws if you try to update UI from the wrong thread. Stability. What an interesting concept. -- Chris Maunder

                  N Offline
                  N Offline
                  Nick Parker
                  wrote on last edited by
                  #8

                  Yep, your right, I can do it in .NET 1.1 but 2.0 doesn't like it. In fact, Visual Studio shows this error: - Nick Parker
                  My Blog | My Articles

                  1 Reply Last reply
                  0
                  Reply
                  • Reply as topic
                  Log in to reply
                  • Oldest to Newest
                  • Newest to Oldest
                  • Most Votes


                  • Login

                  • Don't have an account? Register

                  • Login or register to search.
                  • First post
                    Last post
                  0
                  • Categories
                  • Recent
                  • Tags
                  • Popular
                  • World
                  • Users
                  • Groups