在AsyncCallback(控制台应用程序)内的原始线程上触发事件

时间:2012-01-17 20:39:34

标签: c# .net asynchronous synchronization threadpool

我正在使用Func<>或Action<> .BeginInvoke使用ThreadPool异步运行方法。

是否有可能让AsyncCallback在产生新线程的原始线程上调用一个函数(或技术上的事件)?

我知道在WinForms应用程序中,您可以使用Control / ISynchronizeInvoke / Dispatcher在异步操作完成时警告UI线程 - 但这不是WinForms应用程序,它似乎不起作用。

    class SyncTest : System.ComponentModel.ISynchronizeInvoke
    {
        public void TestMethod() {
            Console.WriteLine(System.Threading.Thread.CurrentThread.ManagedThreadId + " Test Method Fired.");
        }

        public IAsyncResult BeginInvoke(Delegate method, object[] args) {
            throw new NotImplementedException();
        }

        public object EndInvoke(IAsyncResult result) {
            throw new NotImplementedException();
        }

        public object Invoke(Delegate method, object[] args) {
            return method.DynamicInvoke(args); 
        }

        public bool InvokeRequired {
            get { throw new NotImplementedException(); }
        }

        public void Test()
        {
            var sleep = new Action(() => System.Threading.Thread.Sleep(5000));

            System.ComponentModel.ISynchronizeInvoke originalThreadCallback = (System.ComponentModel.ISynchronizeInvoke)this;

            for (int i = 0; i < 5; i++)
            {
                sleep.BeginInvoke(new AsyncCallback(res =>
                {
                    (res.AsyncState as Action).EndInvoke(res);
                    Console.WriteLine("Thread inside callback: " + System.Threading.Thread.CurrentThread.ManagedThreadId); 
                    originalThreadCallback.Invoke(new Action(() => this.TestMethod()), null);
                }), sleep);
            }
        }
    }

Test()方法的输出如下:

主线程= 9

TEST DONE

回调中的线程:11

回调中的线程:10

10种测试方法被解雇。

11测试方法被解雇。

回调中的线程:12

12测试方法被解雇。

回调中的线程:13

13测试方法被解雇。

回调中的线程:14

14测试方法被解雇。

正如您所看到的,ID = 9的原始线程上没有调用任何内容。

显然我的ISynchronizeInvoke实现实际上没有做任何事情来调用原始线程上的Test方法,这就是问题所在 - 但我似乎也无法从我的任何委托或事件中获取ISynchronizeInvoke实例(它总是为空)。 .NET 4中的哪些对象正确实现了接口?

感谢。

1 个答案:

答案 0 :(得分:2)

好吧,你必须有一些循环,就像Windows Forms(等)那样,等待工作处理。

可以自己编写,但这意味着你的原始线程必须保持相对自由,就像你不想阻止Windows窗体应用程序中的UI线程一样。基本上,您将重写WinForms使用的一些基础结构。虽然.NET 4生产者/消费者队列类(例如BlockingCollection<T>)至少帮助,但我没有意识到这只是开箱即用的。

BlockingCollection<T>的文档给出了一个如何实现生产者/消费者队列的快速示例 - 基本上你的线程池线程会在队列上调用Add,而你的消费者线程会调用Take在它上面(或TryTake)。

还有一个Channel-9 video与专家Stephen Toub(MS中的并行团队)关于使用BlockingCollection