Skip to content

DoInvokes called from a task on a non-inlining TaskScheduler runs Invoke/InvokeAsync delegates off the owner thread, or deadlocks: task.RunSynchronously() uses TaskScheduler.Current #65

Closed

Description

@matt-edmondson

What's wrong

DoInvokes drains the queue with task.RunSynchronously(); (Invoker/Invoker.cs:204). With no argument, RunSynchronously targets TaskScheduler.Current. When DoInvokes is itself called from inside a task running on a custom scheduler whose TryExecuteTaskInline returns false, the task is queued back to that scheduler, and DoInvokes blocks until it runs somewhere else.

Repro

Scheduler hands work to the thread pool and refuses to inline. The owner loop runs as a task on this scheduler. Another thread calls inv.Invoke(...), then the owner calls inv.DoInvokes():

owner thread=4, Invoke'd action ran on thread=7, sameThread=False
RunSynchronously(TaskScheduler.Default) ran on 4, sameThread=True

Single dedicated-thread scheduler that refuses to inline. The owner is that scheduler's only thread:

DoInvokes still blocked after 3s (deadlock)

Why it matters

The library exists to guarantee that queued delegates run on the owner thread. In the first case that guarantee silently breaks, and code that touches thread-affine state runs on a pool thread. In the second case the owner thread hangs forever. TaskScheduler.FromCurrentSynchronizationContext() does inline on its own thread, so typical WPF/WinForms apps are not affected. Custom "dedicated thread" or limited-concurrency schedulers used for game loops and actors are.

Suggested fix

Use task.RunSynchronously(TaskScheduler.Default). The default scheduler always allows inlining here, and the repro confirms it then runs on the owner thread. An alternative is to stop using Task for the queue and complete a TaskCompletionSource after invoking the delegate directly.

Acceptance criteria

  • A test that calls DoInvokes from inside a task on a scheduler that refuses to inline asserts the delegate ran on the owner thread and that DoInvokes returns.

Activity

  1. matt-edmondson commented on Sep 29, 2026

    @matt-edmondson
    ContributorAuthor

    Triage


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

bugSomething isn't working

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions