使用线程非常简单 Thread thread = new Thread(MethodWhichRequiresSTA); thread.SetApartmentState(ApartmentState.STA); 如何使用WPF应用程序中的任务来完成相同的任务? 这里是一些代码: Task.Factory.StartNew ( () => {return "some Text";} ) .ContinueWith(r => AddControlsToGrid(r.Result)); 我得到一个InvalidOperationException 调用线程必须是STA,因为许多UI组件都需要这个。
这是什么意思,如何解决? 我正在使用TPL任务。 整个错误 通过等待任务或访问它的Exception属性,没有观察到任务的exception。 结果,终结者线程重新抛出了未观察到的exception。 在System.Threading.Tasks.TaskExceptionHolder.Finalize() mscorlib程序
有时,一旦我用CancellationTokenSource.Cancel请求取消挂起的任务,我需要确保任务已经正确到达取消状态 ,然后才能继续。 我经常遇到这种情况,当应用程序正在终止,我想优雅地取消所有挂起的任务。 但是,当新的后台进程只有在当前未完成的进程已经被完全取消或自然到达时才能启动,这也可以是UI工作stream规范的要求。 如果有人分享他/她的处理这种情况的方法,我将不胜感激。 我正在谈论以下模式: _cancellationTokenSource.Cancel(); _task.Wait(); 就像这样,在UI线程上使用它时很容易导致死锁。 但是,并不总是可以使用asynchronous等待(即await task ;例如,这是可能的情况之一)。 与此同时,简单地请求取消并且继续而不实际观察其状态是一种代码味道。 作为一个简单的例子来说明这个问题,我可能想确保在FormClosing事件处理程序中完全取消了以下的DoWorkAsync任务。 如果我不等待MainForm_FormClosing的_task ,我甚至可能不会看到当前工作项目的"Finished work item N"跟踪,因为应用程序终止于待处理子任务的中间(在池线程)。 如果我真的等待,结果会陷入僵局: public partial class MainForm : Form { CancellationTokenSource _cts; Task _task; // Form Load event void MainForm_Load(object sender, EventArgs e) { _cts = new CancellationTokenSource(); _task = DoWorkAsync(_cts.Token); } // Form Closing event void MainForm_FormClosing(object […]
使用System.Threading.Tasks.Task<TResult> ,我必须pipe理可能抛出的exception。 我正在寻找最好的方法来做到这一点。 到目前为止,我创build了一个基类来pipe理.ContinueWith(…)调用中的所有未捕获的exception.ContinueWith(…) 我想知道是否有更好的方法做到这一点。 或者即使这是一个很好的方法来做到这一点。 public class BaseClass { protected void ExecuteIfTaskIsNotFaulted<T>(Task<T> e, Action action) { if (!e.IsFaulted) { action(); } else { Dispatcher.CurrentDispatcher.BeginInvoke(new Action(() => { /* I display a window explaining the error in the GUI * and I log the error. */ this.Handle.Error(e.Exception); })); } } } public class ChildClass : […]
我从一个函数开始一个新的任务,但我不希望它在同一个线程上运行。 我不关心它运行在哪个线程,只要它是一个不同的线程(所以在这个问题给出的信息不起作用)。 我保证,下面的代码将总是退出TestLock之前允许Task t再次进入它? 如果不是,build议的devise模式是什么,以防止重复? object TestLock = new object(); public void Test(bool stop = false) { Task t; lock (this.TestLock) { if (stop) return; t = Task.Factory.StartNew(() => { this.Test(stop: true); }); } t.Wait(); } 编辑:根据Jon Skeet和Stephen Toub的下面的答案,确定性地防止重入的一个简单方法是传递一个CancellationToken,如下面的扩展方法所示: public static Task StartNewOnDifferentThread(this TaskFactory taskFactory, Action action) { return taskFactory.StartNew(action: action, cancellationToken: new CancellationToken()); }
我想触发一个任务在后台线程上运行。 我不想等任务完成。 在.net 3.5中我会这样做: ThreadPool.QueueUserWorkItem(d => { DoSomething(); }); 在.net 4中,TPL是build议的方式。 我见过的常见模式是: Task.Factory.StartNew(() => { DoSomething(); }); 但是, StartNew()方法返回一个实现IDisposable的Task对象。 这似乎被推荐这种模式的人忽视了。 Task.Dispose()方法的MSDN文档说: “在释放您最后一次引用任务之前,请始终调用Dispose。” 在完成任务之前,您不能调用任何处理任务,因此让主线程等待并调用处理器将首先打败后台线程。 也似乎没有任何完成/完成的事件可以用于清理。 Task类中的MSDN页面不对此进行评论,而“Pro C#2010 …”这本书推荐了相同的模式,并没有对任务处理进行评论。 我知道如果我只是离开它,终结者将抓住它,但是当我正在做这样的大火和忘记任务,并且终结者线程被淹没时,这是否会回来咬我? 所以我的问题是: 在这种情况下,不要在Task类上调用Dispose()是否可以接受? 如果是这样,为什么还有风险/后果? 有没有任何文件讨论这个? 或者有没有适当的方式处理我错过的Task对象? 还是有另一种方式与TPL做火和忘记任务?
某些System.Threading.Tasks.Task构造函数将CancellationToken作为参数: CancellationTokenSource source = new CancellationTokenSource(); Task t = new Task (/* method */, source.Token); 让我感到困惑的是,从方法体内部无法实际获取传入的令牌(例如,没有像Task.CurrentTask.CancellationToken )。 令牌必须通过一些其他机制来提供,比如状态对象或者在lambda中捕获。 那么在构造函数中提供取消标记的目的是什么?
我正在玩这些Windows 8的WinRT任务,我试图用下面的方法取消一个任务,这个任务很有用。 CancelNotification方法被调用,这使得你认为任务被取消了,但是在后台任务继续运行,然后在任务完成之后,任务的状态总是被完成并且不会被取消。 有没有办法在取消任务时完全停止任务? private async void TryTask() { CancellationTokenSource source = new CancellationTokenSource(); source.Token.Register(CancelNotification); source.CancelAfter(TimeSpan.FromSeconds(1)); var task = Task<int>.Factory.StartNew(() => slowFunc(1, 2), source.Token); await task; if (task.IsCompleted) { MessageDialog md = new MessageDialog(task.Result.ToString()); await md.ShowAsync(); } else { MessageDialog md = new MessageDialog("Uncompleted"); await md.ShowAsync(); } } private int slowFunc(int a, int b) { […]
这个问题已经被EF数据上下文 – asynchronous/等待和multithreading触发。 我已经回答了一个,但没有提供任何最终解决scheme。 原来的问题是有很多有用的.NET API(比如Microsoft Entity Framework的DbContext ),它提供了asynchronous方法,用于await ,但它们被logging为不是线程安全的 。 这使得它们非常适合在桌面UI应用程序中使用,但不适用于服务器端应用程序。 [EDITED] 这实际上可能不适用于DbContext ,这里是微软对DbContext 线程安全性的陈述 ,请DbContext判断。 [/ EDITED] 还有一些已经build立的代码模式属于同一类别,比如使用OperationContextScope调用WCF服务代理( 在这里和这里问),例如: using (var docClient = CreateDocumentServiceClient()) using (new OperationContextScope(docClient.InnerChannel)) { return await docClient.GetDocumentAsync(docId); } 这可能会失败,因为OperationContextScope在其实现中使用线程本地存储。 问题的根源是AspNetSynchronizationContext ,用于asynchronousASP.NET页面,以便从ASP.NET线程池执行更多的线程数更less的HTTP请求。 使用AspNetSynchronizationContext ,可以将await继续排队在与启动asynchronous操作的线程不同的线程上,同时将原始线程释放到池中,并可用于服务另一个HTTP请求。 这大大提高了服务器端代码的可伸缩性。 该机制在“所有关于同步上下文”中有详细描述, 这是一个必读内容。 所以,虽然没有涉及到并发的API访问 ,但潜在的线程切换仍然阻止我们使用上述的API。 我一直在考虑如何解决这个问题,而不牺牲可扩展性。 显然,这些API返回的唯一方法是维护线程切换可能影响的asynchronous调用范围的线程关系 。 比方说,我们有这样的线程亲和力。 这些调用大部分都是IO绑定( 没有线程 )。 asynchronous任务处于待处理状态时,可以使用它发起的线程来继续执行另一个类似的任务,该结果已经可用。 因此,它不应该伤害可扩展性太多。 这种方法并不新鲜,事实上, Node.js成功地使用了一个类似的单线程模型 […]
我很高兴在.NET 4.0中看到新的System.Collections.Concurrent命名空间,相当不错! 我见过ConcurrentDictionary , ConcurrentQueue , ConcurrentStack , ConcurrentBag和BlockingCollection 。 似乎神秘缺失的一件事是ConcurrentList<T> 。 我必须自己写(或从网上下载:))? 我在这里错过了很明显的东西吗