有没有办法在非WPF线程上使用Dispatcher?多线程新手 [英] Is there any way to use Dispatcher on a non WPF thread ; new to multi threading

查看:52
本文介绍了有没有办法在非WPF线程上使用Dispatcher?多线程新手的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

为什么这不起作用?

我正在尝试做的事情:我需要一种在特定线程中运行特定方法的方法,该线程一直存在到程序结束.

What I am trying to do: I need a way to run specific methods in a specific thread that lives on till the end of the program.

我其他可能的选择:据我了解,一种可行的方法是实现队列.我可以将要在特定线程中运行的方法推入到其中.在特定的线程中,我将旋转并进入睡眠状态/monitor.pulse,以查看队列中是否有等待运行的委托.

My other possible options: As I understand a possible way to do it would be to implement a queue. Into which I could push in methods I want to be run in the specific thread. In the specific thread, I would be spinning and sleeping / monitor.pulse to see if there are delegates waiting to be run in the queue.

我的目标:是为了避免创建委托队列,维护锁定等所有繁琐的工作.看来WPF世界中存在一个名为Dispatcher的现成解决方案.WPF控件大部分都继承自DispatcherObject,并且某种程度上可以使整个事情正常进行.我该怎么做才能完成这项工作?

My objective: Is to avoid all the hardwork to create the delegate queue, maintain lock etc. It appears that a ready made solution exists in the WPF world called Dispatcher. WPF controls mostly inherit from DispatcherObject and somehow the whole thing works. What do I have to do to get this work?

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

namespace ThreadingTrials
{
    class Program
    {
        [STAThread]
        static void Main(string[] args)
        {
            Thread.CurrentThread.Name = "mainThread";
            Engine engine = new Engine();
            Console.WriteLine("initializing SpecialEngine from {0}", Thread.CurrentThread.Name);
            engine.initialize();
            engine.doWork();
        }
    }
    class Engine:DispatcherObject
    {
        private EventWaitHandle InitializationComplete;
        private EventWaitHandle newWorkComplete;
        //private Dispatcher dispatcher;
        public Engine()
        {

        }
        public void initialize()
        {
            InitializationComplete = new EventWaitHandle(false, EventResetMode.ManualReset);
            Thread thread = new Thread(new ParameterizedThreadStart((hwnd)=>
            {
                InitializeSpecialEngineObject();
                while (true) ;
            }));
            thread.Name = "Special Engine Thread";

            thread.SetApartmentState(ApartmentState.STA);
            thread.Priority = ThreadPriority.Normal;
            thread.Start();
            Console.WriteLine("waiting for initialize at {0}", Thread.CurrentThread.Name);
            InitializationComplete.WaitOne();
        }
        private void InitializeSpecialEngineObject()
        {
            Console.WriteLine("doing initialization at {0}", Thread.CurrentThread.Name);
            Thread.Sleep(500);
            //dispatcher = Dispatcher.CurrentDispatcher;
            InitializationComplete.Set();
        }

        internal void doWork()
        {
            newWorkComplete = new EventWaitHandle(false, EventResetMode.AutoReset);
            //Dispatcher.Thread.Suspend();
            Dispatcher.Invoke((SendOrPostCallback)delegate
                {
                    Console.WriteLine("dispatched to {0}", Thread.CurrentThread.Name);
                    Thread.Sleep(500);
                    newWorkComplete.Set();
                },DispatcherPriority.Background, null);
            Dispatcher.Thread.Resume();
            Console.WriteLine("waiting for new work to complete at {0}", Thread.CurrentThread.Name);
            newWorkComplete.WaitOne();
        }
        private void doingWork()
        {
            Console.WriteLine("Doing work in {0}", Thread.CurrentThread.Name);

            Thread.Sleep(500);
        }
    }
}

感谢您的输入.很公平.创建一个简单的工作线程来等待一个事件,该事件在void()委托队列中等待一个新任务,并在它们可用时运行它们,这实际上是很少的工作.我从在线网站上复制了大部分代码...对不起,丢失了参考.我是在那天完成的,应该早些编辑这篇文章.

Thanks for the input. Fair enough. It was actually very little work to make a simple worker thread that waits for an event signifying a new task in queue of void() delegates, and runs them as they become available. I copied most of the code from a website online... Sorry lost reference. I had done it on that day, and should have edited this post earlier.

using System;
using System.Threading;
using System.Collections.Generic;

class ProducerConsumerQueue : IDisposable
{
    EventWaitHandle _wh = new AutoResetEvent(false);
    Thread _worker;
    readonly object _locker = new object();
    Queue<Action> _tasks = new Queue<Action>();

    public delegate void Action();

    public ProducerConsumerQueue()
    {
        _worker = new Thread(Work);
        _worker.Start();
    }

    public void EnqueueTask(Action work)
    {
        lock (_locker) _tasks.Enqueue(work);
        _wh.Set();
    }

    public void Dispose()
    {
        EnqueueTask(null);     // Signal the consumer to exit.
        _worker.Join();         // Wait for the consumer's thread to finish.
        _wh.Close();            // Release any OS resources.
    }

    void Work()
    {
        while (true)
        {
            Action task = null;
            lock (_locker)
                if (_tasks.Count > 0)
                {
                    task = _tasks.Dequeue();
                    if (task == null) return;
                }
            if (task != null)
            {
                task.Invoke();
            }
            else
                _wh.WaitOne();         // No more tasks - wait for a signal
        }
    }

}
class Program
{
    static void Main()
    {
        using (ProducerConsumerQueue q = new ProducerConsumerQueue())
        {
            q.EnqueueTask(delegate 
            {
                Console.WriteLine("Performing task: Hello");
                Thread.Sleep(1000);  // simulate work...
            });
            for (int i = 0; i < 10; i++) q.EnqueueTask(delegate 
            {
                Console.WriteLine("Performing task: "+ i);
                Thread.Sleep(1000);  // simulate work...
            });
            q.EnqueueTask(delegate 
            {
                Console.WriteLine("Performing task: Goodbye!");
                Thread.Sleep(1000);  // simulate work...
            });
        }

        // Exiting the using statement calls q's Dispose method, which
        // enqueues a null task and waits until the consumer finishes.
    }
}

推荐答案

您不会调用 Dispatcher.Run .您假设一个 Dispatcher 包含一个完成工作的 Thread ,但这是倒退的.第一次调用 Dispatcher.CurrentDispatcher 时,会绑定到当前线程来创建 Dispatcher .请注意,即使您的代码没有直接调用 CurrentDispatcher ,它也会通过构造 DispatcherObject (将 CurrentDispatcher 捕获到一个字段中)来间接调用此代码.).

You don't call Dispatcher.Run. You're assuming that a Dispatcher contains a Thread that does its work, but this is backwards. The first time that Dispatcher.CurrentDispatcher is called, a Dispatcher is created bound to the current thread. Note that even though your code doesn't call CurrentDispatcher directly, it does do so indirectly by constructing a DispatcherObject (which captures CurrentDispatcher into a field).

查看 WPF线程模型文档,其中包含所有您需要的详细信息.

Review the WPF threading model docs, which contain all the details you need.

如果您想在子线程中使用类似调度程序的功能,但又不想依赖WPF,则可以使用ActionThread 类.codeplex.com/"rel =" nofollow noreferrer> Nito.Async ,大致相当于 Dispatcher 加上专用的 Thread .

If you want dispatcher-like functionality in a child thread but don't want to take a dependency on WPF, you can use the ActionThread class from Nito.Async, which is roughly equivalent to a Dispatcher plus a dedicated Thread.

这篇关于有没有办法在非WPF线程上使用Dispatcher?多线程新手的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆