Sunday, June 27, 2010

Invoke code on a certain thread in C# / .NET

Virtually all GUI frameworks and the languages that come with them give you the possibility to invoke a certain piece of code on the UI thread. This is necessary because the UI components aren't usually thread safe (making all their methods thread safe would be a big blow to the performance of the application), so any update of the UI can't be done from another thread. That piece of code needs to be marshalled to the main thread.
.NET goes a step further and offers us the possibility to invoke a piece of code on any thread. The example bellow shows how this can be done.
ThreadTask will be run in a new thread, whose name is "Alpha thread". We create a Control on this thread (new Control()) and then we create its handle: ctrl.CreateControl().
Finally, we do Application.Run(), which makes our thread wait for messages in the message loop.
Then we use our control to invoke the method MyTestMethod on our thread.

Note that control handle creation is essential; without it, MyTestMethod would be invoked on the main thread. Also, attaching the thread to the message loop by doing Application.Run() ensures that the thread waits for invokes from other threads.



using System;
using System.Windows.Forms;
using System.Threading;

namespace TestThreads2 {
    public class TestThread {
        private Control ctrl = null;

        // This method that will be called when the thread
        // is started
        public void ThreadTask() {
            if (ctrl == null) {
                // create the control
                ctrl = new Control();
                // create the handle
                ctrl.CreateControl();
            }
            Console.WriteLine("ThreadTask is running on thread: " +
                Thread.CurrentThread.Name);
            // ensure the message loop is attached to this thread
            Application.Run();
        }

        public Control Ctrl {
            get { return ctrl; }
            set { ctrl = value; }
        }
    }

    public class Program {
        private static void MyTestMethod() {
            Console.WriteLine("TestMethod invoked on thread: " +
                Thread.CurrentThread.Name);
        }

        static void Main(string[] args) {
            //Control.CheckForIllegalCrossThreadCalls = true;
            TestThread myThread = new TestThread();
            Thread thread =
                new Thread(
                    new ThreadStart(myThread.ThreadTask)
                );
            thread.Name = "Alpha thread";
            thread.Start();
            Thread.Sleep(1000);
            if (myThread.Ctrl.InvokeRequired) {
                myThread.Ctrl.BeginInvoke(
                    new MethodInvoker(MyTestMethod)
                );
            } else {
                MyTestMethod();
            }
        }
    }
}




Check out here how to do the same thing in Java.

No comments:

Post a Comment