Task.Factory.StartNew ignores Task.WaitAll

本文关键字:Task WaitAll ignores StartNew Factory | 更新日期: 2023-09-27 17:57:19

我在使用Task.Factory.StartNew和Task.WaitAll时遇到了一些问题。任务确实按预期启动,但看起来它只是忽略了 Task.WaitAll,因为在单击我的按钮(这是此代码所在的事件)后,MessageBox 已经弹出。

List<Task> tasks = new List<Task>();
        if (plugin.UseProxy)
        {
            foreach (var item in combo)
            {
                Task.Factory.StartNew(() =>
                {
                    // Some code
                }).ContinueWith((t) =>
                {
                    tasks.Add(t);
                    pbProgress.Value++;
                }, TaskScheduler.FromCurrentSynchronizationContext());
            }
        }
        else
        {
            foreach (var item in combo)
            {
                Task.Factory.StartNew(() =>
                {
                    // Some code
                }).ContinueWith((t) =>
                {
                    tasks.Add(t);
                    pbProgress.Value++;
                }, TaskScheduler.FromCurrentSynchronizationContext());
            }
        }
        Task.WaitAll(tasks.ToArray());
        MessageBox.Show("Hello");

Task.Factory.StartNew ignores Task.WaitAll

只有在任务完成后,您才能将任务添加到列表中。 ContinueWith任务完成后执行。因此,Task.WaitAll正在等待一个空的任务列表。

所以你可以这样做:

Task task = Task.StartNew(() =>
{
    // Some code
}).ContinueWith((t) =>
{
    pbProgress.Value++;
}, TaskScheduler.FromCurrentSynchronizationContext());
tasks.Add(task);

只有在线程通过StartNew启动后,tasks列表才会获得添加到其中的项目。您遇到的问题是您在将项目添加到集合之前点击了Task.WaitAll(tasks.ToArray());。您需要将项目添加到创建它们的线程中的集合中,而不是在继续,

var newTask = Task.Factory.StartNew(() =>
{
    // Some code
});
tasks.Add(newTask);
newTask.ContinueWith((t) =>
{
    pbProgress.Value++;
}, TaskScheduler.FromCurrentSynchronizationContext());

但是,您的代码也有其他问题。您永远不会将TaskSchedueller传递给工厂,否则很容易意外地在 UI 线程上启动线程。此外,我假设此代码在 UI 线程上运行,您的Task.WaitAll将阻止 UI 线程。如果其中一个StartNew线程最终位于 UI 线程上,这可能会导致死锁。