0

我有一个抛出事件的工作线程,这些事件由常见的处理程序方法处理,实际上我想实现处理程序方法由创建包含抛出事件的工作线程的对象的线程执行。

我尝试了以下代码:

public partial class Form1 : Form
{
    public event EventHandler Tested;

    public Form1()
    {
        InitializeComponent();

        Tested += new EventHandler(Form1_Tested);
    }

    private void Form1_Tested(object sender, EventArgs e)
    {
        Text = "Test";
    }

    private void Form1_Shown(object sender, EventArgs e)
    {
        #region Test 1
        // Works normal in GUI-Thread directly
        Form1_Tested(this, EventArgs.Empty);
        #endregion

        #region Test 2
        // Works in worker thread and throws GUI exception 
        // because of foreign thread access
        new Thread(new ThreadStart(delegate()
            {
                OnTested(EventArgs.Empty);
            })).Start();
        #endregion

        #region Test 3
        // Works in worker thread and returns to GUI-Thread
        // to throw the event, so no need in eventhandler 
        // to use Control.Invoke();
        AsyncOperation asyncOp = AsyncOperationManager.CreateOperation(null);
        new Thread(new ThreadStart(delegate()
            {
                asyncOp.Post(new SendOrPostCallback(delegate(object obj)
                    {
                        OnTested(EventArgs.Empty);
                    }), null);
            })).Start();
        #endregion
    }

    protected virtual void OnTested(EventArgs e)
    {
        EventHandler tmpHandler = Tested;
        if (tmpHandler != null)
            tmpHandler(this, e);
    }
}

我仔细查看了我使用的线程

Thread.CurrentThread.ManagedThreadId;

在启动工作线程之前,我的主线程的 id 是“1”。在 UI 线程中,就在触发事件之前,线程 ID(工作线程)是“4”。现在仔细查看处理程序方法中的线程 ID,线程 ID 类似于“10” - 但我希望 ID 为“1”。我对此很困惑。

一般来说:我的代码片段是正确的方法吗,或者这样做的最佳实践是什么(甚至是一个工作示例)?

实际上,我想避免在工作线程上使用 Invoke。

问候,托马斯

4

1 回答 1

1

您可以使用 Task<> 代替委托吗?我认为如果可以的话,它可能会为您简化事情。

基本上,如果您创建一个 Task<>,您可以通过访问 .Result 属性来访问该任务的结果,该属性将等待线程完成,然后给您返回码,或者 - 如果线程抛出异常 - 将在访问 .Result 属性的线程的上下文中重新抛出该异常。

(如果你的线程没有返回任何东西,你可以调用 Task.Wait() 而不是访问 .Result)

一些代码可能有助于解释我的意思:

using System;
using System.Threading;
using System.Threading.Tasks;

namespace Demo
{
    class Program
    {
        static void Main(string[] args)
        {
            var task = new Task<int>(() => test(1000, "Test1"));
            tryTask(task);

            task = new Task<int>(() => test(2000, "Test2"));
            tryTask(task);

            task = new Task<int>(() => test(1, "Test2"));
            tryTask(task);
        }

        static void tryTask(Task<int> task)
        {
            task.Start();

            try
            {
                Console.WriteLine("Task result = " + task.Result);
            }

            catch (AggregateException ex)
            {
                Console.WriteLine("Task threw an exception: " + ex.InnerException.Message);
            }
        }

        static int test(int value, string name)
        {
            Console.WriteLine("Starting thread " + name);
            Thread.Sleep(value);
            Console.WriteLine("Ending thread " + name);

            if (value == 1) // Magic number!
            {
                throw new InvalidOperationException("Test Exception");
            }

            return value;
        }
    }
}
于 2012-06-21T12:56:42.307 回答