是否可以将事件处理程序放在与调用者不同的线程上?

Rob*_*ray 10 c# events multithreading delegates

假设我有一个名为Tasking的组件(我无法修改),它暴露了一个方法"DoTask",它执行一些可能冗长的计算并通过事件TaskCompleted返回结果.通常,这是在用户在获得结果后关闭的窗体中调用的.

在我的特定场景中,我需要将一些数据(数据库记录)与TaskCompleted中返回的数据相关联,并使用它来更新数据库记录.

我已经调查了使用AutoResetEvent来处理事件的时间.问题是AutoResetEvent.WaitOne()将阻塞,永远不会调用事件处理程序.通常,AutoResetEvents被称为一个单独的线程,所以我想这意味着事件处理程序与调用的方法位于同一个线程上.

本质上我想通过阻塞将异步调用(通过事件返回结果)转换为同步调用(即从另一个类调用DoSyncTask),直到处理事件并将结果放在事件处理程序可访问的位置以及调用启动异步调用的方法的方法.

public class SyncTask
{
    TaskCompletedEventArgs data;
    AutoResetEvent taskDone;

public SyncTask()
{
    taskDone = new AutoResetEvent(false);
}

public string DoSyncTask(int latitude, int longitude)
{
    Task t = new Task();
    t.Completed = new TaskCompletedEventHandler(TaskCompleted);
    t.DoTask(latitude, longitude);
    taskDone.WaitOne(); // but something more like Application.DoEvents(); in WinForms.
    taskDone.Reset();
    return data.Street;
}

private void TaskCompleted(object sender, TaskCompletedEventArgs e)
{
    data = e;
    taskDone.Set(); //or some other mechanism to signal to DoSyncTask that the work is complete.
}
}

In a Windows App the following works correctly.

public class SyncTask
{
    TaskCompletedEventArgs data;

public SyncTask()
{
    taskDone = new AutoResetEvent(false);
}

public string DoSyncTask(int latitude, int longitude)
{
    Task t = new Task();
    t.Completed = new TaskCompletedEventHandler(TaskCompleted);
    t.DoTask(latitude, longitude);
    while (data == null) Application.DoEvents();

    return data.Street;
}

private void TaskCompleted(object sender, TaskCompletedEventArgs e)
{
    data = e;
}
}
Run Code Online (Sandbox Code Playgroud)

我只需要在窗口服务中复制该行为,其中未调用Application.Run且ApplicationContext对象不可用.

Jas*_*own 2

也许您可以让 DoSyncTask 启动一个计时器对象,以某个适当的时间间隔检查数据变量的值。一旦数据具有值,您就可以触发另一个事件来告诉您数据现在具有值(当然并关闭计时器)。

相当丑陋的黑客,但它可以工作......在理论上。

抱歉,这是我半睡半醒时能想到的最好办法了。该睡了...