简体   繁体   中英

Run code in a specific thread

I have a console application which talks to an external library. Unfortunately all calls to the library must be made from the same thread.

How can I send method calls from one thread to another? (And, obviously, send the method results back to the calling thread.)

(No, this isn't to do with GUI programming. No, using the GUI message pump won't work.)

What I really want is for every single method on a particular class to always be executed in the same thread. But I have no idea how to do that.

My advice is to do what Windows Forms and WPF do to set up their single threaded message pumps - inherit SynchronizationContext . http://msdn.microsoft.com/en-us/library/system.threading.synchronizationcontext%28v=vs.110%29.aspx

In your implementation, you will need to maintain a thread safe message queue, similar to this one: http://www.codeproject.com/Articles/56369/Thread-safe-priority-queue-in-C Your message pump worker thread will constantly check for new delegates, and invoke them.

So why not just write a message pump?

Well, by inheriting SynchronizationContext , you get all the CLR goodies like BackgroundWorker , AsyncOperationManager and the new await/async pattern keyword for free! They will all magically join back to your library thread.

Here is some code for a basic message pump. It does not implement SynchronizationContext :

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;

namespace MessagePump
{
    class Program
    {
        static void Main(string[] args)
        {
            MessagePump p = new MessagePump();
            p.Start();
            p.AddMessage(() => Console.WriteLine("message 1"));
            p.AddMessage(() => Console.WriteLine("message 2"));
            p.AddMessage(() => Console.WriteLine("message 3"));

            Console.ReadLine();
            p.Stop();
        }
    }

    class MessagePump
    {
        bool m_Working = false;
        Queue<Action> m_Actions = new Queue<Action>();

        public void Start()
        {
            m_Working = true;
            Thread t = new Thread(DoPump);
            t.Name = "Message Pump Thread";
            t.Start();
        }
        void DoPump()
        {
            while (m_Working)
            {
                try
                {
                    Monitor.Enter(m_Actions);
                    while (m_Actions.Count > 0)
                    {
                        m_Actions.Dequeue()(); //dequeue and invoke a delegate
                    }
                }
                finally
                {
                    Monitor.Exit(m_Actions);
                }

                Thread.Sleep(100); //dont want to lock this core!
            }
        }
        public void Stop()
        {
            m_Working = false;
        }

        public void AddMessage(Action act)
        {
            lock (m_Actions)
            {
                m_Actions.Enqueue(act);
            }
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM