Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/293.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/21.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# TaskScheduler.Default是否不总是保证任务将在池线程上执行?_C#_.net_Task Parallel Library_Async Await_Task - Fatal编程技术网

C# TaskScheduler.Default是否不总是保证任务将在池线程上执行?

C# TaskScheduler.Default是否不总是保证任务将在池线程上执行?,c#,.net,task-parallel-library,async-await,task,C#,.net,Task Parallel Library,Async Await,Task,TaskScheduler.Default是否始终保证任务将在池线程上执行 在修复一个bug时,我发现至少有一个bug不存在。它可以这样复制(一个由真实代码制作的人为示例): var tcs=new TaskCompletionSource(); var sc=SynchronizationContext.Current; sc.Post(=>tcs.SetResult(true),null); 等待tcs.Task.ContinueWith(=> { //在这里休息 Assert(Thread

TaskScheduler.Default
是否始终保证任务将在池线程上执行

在修复一个bug时,我发现至少有一个bug不存在。它可以这样复制(一个由真实代码制作的人为示例):

var tcs=new TaskCompletionSource();
var sc=SynchronizationContext.Current;
sc.Post(=>tcs.SetResult(true),null);
等待tcs.Task.ContinueWith(=>
{
//在这里休息
Assert(Thread.CurrentThread.IsThreadPoolThread);
}, 
取消令牌。无,
TaskContinuationOptions.ExecuteSynchronously,TaskScheduler.Default);
还有其他情况吗

另外,如果先行任务已在池线程上完成,或者排队进入线程池,是否有一种优雅的方法确保同步执行
ContinueWith
操作(我知道我可以在
ContinueWith
操作中使用
QueueUserWorkItem
,但我不喜欢它)


编辑后,我想我可以实现自己的
TaskScheduler
,并检查我是否已经在
TryExecuteTaskInline
内的线程池线程上,以控制这一点。

我认为发生这种情况的原因是因为您使用了
TaskContinuationOptions.ExecuteSynchronously
。从文件:

ExecuteSynchronous指定继续任务应为 同步执行。指定此选项后,将继续 将在导致antecedent任务停止的同一线程上运行 过渡到其最终状态。如果先行项已经完成 创建延续时,延续将在 创建延续的线程。只有很短的时间 continuations应该同步执行

如果antecedent任务在线程池线程以外的线程上完成,则继续也将在该线程上运行。因此,我猜在这种情况下,没有计划发生。另一种情况可能是,延续任务已经完成,它也将同步运行

更新

为了达到问题第二部分的要求,我想你需要一个定制的等待者。有关更多详细信息,请参见e,但类似的内容可能适合您:

public static class Extensions
{
    public static ThreadPoolTaskAwaiter WithThreadPool(this Task task)
    {
        return new ThreadPoolTaskAwaiter(task);
    }

    public class ThreadPoolTaskAwaiter : INotifyCompletion
    {
        private readonly TaskAwaiter m_awaiter;

        public ThreadPoolTaskAwaiter(Task task)
        {
            if (task == null) throw new ArgumentNullException("task");
            m_awaiter = task.GetAwaiter();
        }

        public ThreadPoolTaskAwaiter GetAwaiter() { return this; }

        public bool IsCompleted { get { return m_awaiter.IsCompleted; } }

        public void OnCompleted(Action continuation)
        {
            if (Thread.CurrentThread.IsThreadPoolThread)
            {
                continuation();
            }
            else
            {
                Task.Run(continuation);
            }                
        }

        public void GetResult()
        {
            m_awaiter.GetResult();
        }
    }
}
然后你就这样使用它:

public static async Task Execute()
{          
    await Task.Delay(500).WithThreadPool();

    // does not break here
    if (!Thread.CurrentThread.IsThreadPoolThread)
    {
        Debugger.Break();
    }
}

我理解TaskContinuationOptions.ExecuteSynchronously是原因,但我仍在寻找文章最后一段中问题的答案。我想我可以实现自己的TaskScheduler,并检查我是否已经在TryExecuteTaskInline中的线程池线程上,为了控制这一点,您可能还可以使用自定义等待器。请参阅我的更新。您所说的“…
ContinueWith
操作是同步执行的,如果先行任务已在池线程上完成”,到底是什么意思?同步在这里意味着什么?如果antecedent在池线程上运行,那么它有什么意义呢?另外,您说这个repro案例不在池线程上执行,但它在哪个线程上执行?此代码段是当前同步上下文为Winforms或WPF dispatcher的UI代码的一部分吗
TaskScheduler
SynchronizationContext
有着奇怪的交互作用,这就是为什么您通常使用
TaskScheduler。从CurrentSynchronizationContext
而不是
TaskScheduler。默认值
@Aaronaught,实际代码将第三方代码事件包装为
TaskCompletionSource
。可以在任何线程上触发该事件,包括具有同步上下文的线程。我不想要
TaskScheduler.FromCurrentSynchronizationContext
。我想在线程池上处理
TaskCompletionSource.Task
的完成。我想使用
TaskContinuationOptions.ExecuteSynchronously
作为优化(如果它已经在线程池中),以避免不必要的线程切换。请注意,ExecuteSynchronously永远不能保证在同一线程上同步运行。这是一个提示。@usr,谢谢你的好意。我只是读到了关于当它不是:
public static async Task Execute()
{          
    await Task.Delay(500).WithThreadPool();

    // does not break here
    if (!Thread.CurrentThread.IsThreadPoolThread)
    {
        Debugger.Break();
    }
}