C# 4.0 使用TPL将“一次性”对象安全地传递到UI线程
我们最近采用了TPL作为运行一些繁重后台任务的工具包 这些任务通常会生成一个实现C# 4.0 使用TPL将“一次性”对象安全地传递到UI线程,c#-4.0,task-parallel-library,idisposable,ui-thread,C# 4.0,Task Parallel Library,Idisposable,Ui Thread,我们最近采用了TPL作为运行一些繁重后台任务的工具包 这些任务通常会生成一个实现IDisposable的对象。这是因为它内部有一些操作系统句柄 我希望发生的是,后台线程生成的对象将始终得到正确处理,也就是在切换与应用程序关闭同时发生时 经过一番思考,我写了这样一篇文章: private void RunOnUiThread(Object data, Action<Object> action) { var t = Task.Factory.StartN
IDisposable
的对象。这是因为它内部有一些操作系统句柄
我希望发生的是,后台线程生成的对象将始终得到正确处理,也就是在切换与应用程序关闭同时发生时
经过一番思考,我写了这样一篇文章:
private void RunOnUiThread(Object data, Action<Object> action)
{
var t = Task.Factory.StartNew(action, data, CancellationToken.None, TaskCreationOptions.None, _uiThreadScheduler);
t.ContinueWith(delegate(Task task)
{
if (!task.IsCompleted)
{
DisposableObject.DisposeObject(task.AsyncState);
}
});
}
private void RunOnUiThread(对象数据、操作)
{
var t=Task.Factory.StartNew(操作、数据、CancellationToken.None、TaskCreationOptions.None、\uUIThreadScheduler);
t、 继续(委托(任务)
{
如果(!task.IsCompleted)
{
DisposableObject.DisposeObject(task.AsyncState);
}
});
}
后台任务
调用RunOnUiThread
将其结果传递给UI线程。任务t
在UI线程上调度,并获得传入的数据的所有权。我希望如果由于ui线程的消息泵关闭而导致t
无法执行,则继续将运行,我可以看到任务失败,并自行处理该对象DisposeObject()
是一个帮助程序,它在处理对象之前检查对象是否确实可标识且不为null
可悲的是,它不起作用。如果在创建后台任务t
后关闭应用程序,则不会执行继续
我以前解决过这个问题。当时我正在使用线程池和WPF调度程序在UI线程上发布消息。虽然不太漂亮,但最终还是成功了。我希望TPL在这方面做得更好。如果我能以某种方式告诉TPL,如果它们实现IDisposable,它应该处理所有剩余的AsyncState对象,那就更好了
因此,代码主要是为了说明问题。我想了解任何允许我将一次性对象从后台任务安全地移交给UI线程的解决方案,最好是使用尽可能少的代码 看看RX库。这可以让您做您想做的事情。看看RX库。这可以让您做您想做的事。来自:
IsCompleted
当任务位于三个选项之一时,将返回true
最终状态:RanToCompletion
、Faulted
或cancelled
换句话说,您的DisposableObject.DisposeObject
永远不会被调用,因为在上述条件之一发生后,将始终计划继续。我相信你的意思是:
t.ContinueWith(t => DisposableObject.DisposeObject(task.AsyncState),
TaskContinuationOptions.NotOnRanToCompletion)
(顺便说一句,您可以简单地捕获数据
变量,而不是使用异步状态
属性)
但是,我不会对您希望确保始终发生的事情使用延续。我相信try finally
块在这里更合适:
private void RunOnUiThread2(Object data, Action<Object> action)
{
var t = Task.Factory.StartNew(() =>
{
try
{
action(data);
}
finally
{
DisposableObject.DisposeObject(task.AsyncState);
//Or use a new *foreground* thread if the disposing is heavy
}
}, CancellationToken.None, TaskCreationOptions.None, _uiThreadScheduler);
}
private void RunOnUiThread2(对象数据、操作)
{
var t=Task.Factory.StartNew(()=>
{
尝试
{
行动(数据);
}
最后
{
DisposableObject.DisposeObject(task.AsyncState);
//如果处理量很大,也可以使用新的“前台”线程
}
},CancellationToken.None,TaskCreationOptions.None,\u uiThreadScheduler);
}
来自:
IsCompleted
当任务位于三个选项之一时,将返回true
最终状态:RanToCompletion
、Faulted
或cancelled
换句话说,您的DisposableObject.DisposeObject
永远不会被调用,因为在上述条件之一发生后,将始终计划继续。我相信你的意思是:
t.ContinueWith(t => DisposableObject.DisposeObject(task.AsyncState),
TaskContinuationOptions.NotOnRanToCompletion)
(顺便说一句,您可以简单地捕获数据
变量,而不是使用异步状态
属性)
但是,我不会对您希望确保始终发生的事情使用延续。我相信try finally
块在这里更合适:
private void RunOnUiThread2(Object data, Action<Object> action)
{
var t = Task.Factory.StartNew(() =>
{
try
{
action(data);
}
finally
{
DisposableObject.DisposeObject(task.AsyncState);
//Or use a new *foreground* thread if the disposing is heavy
}
}, CancellationToken.None, TaskCreationOptions.None, _uiThreadScheduler);
}
private void RunOnUiThread2(对象数据、操作)
{
var t=Task.Factory.StartNew(()=>
{
尝试
{
行动(数据);
}
最后
{
DisposableObject.DisposeObject(task.AsyncState);
//如果处理量很大,也可以使用新的“前台”线程
}
},CancellationToken.None,TaskCreationOptions.None,\u uiThreadScheduler);
}
当进程关闭时,它的所有内核句柄都会自动关闭。您不必为此担心:
当进程关闭时,它的所有内核句柄都会自动关闭。您不必为此担心:
实际上我已经看过了。您知道其中的IDisposable
对象有什么特殊处理吗?不知道,但是由于IObservable总是调用OnError或OnCompleted,因此您可以在那里处理它。我明白了。。。。问题是,这在制作人身上并不例外,据我所知,OnError就是为了这个。但我无论如何都会尝试的。。。除非有人提出更好的建议,否则也不要错过派对,但要面向未来的读者和@Chriseyre2000。事实上,有特殊处理。使用类似以下内容创建可观察序列:Observable。使用(()=>new MyDisposable(),d=>action(d)。ToObservable())
一旦序列完成,将处理一次性对象。注意:您可能还希望使用Observable.Defer
,并以类似的方式将序列传递到该序列中。另外,ToObservable
位于System.Reactive.Threading.Tasks
命名空间中。实际上我有