Detached task is occupying the main thread after returning from awaiting a main actor function

Hi everybody,

our team is currently developing an AppKit-based Mac application. Last week, we discovered a very irritating behaviour with detached tasks and the MainActor:

If you start a detached task which at some point performs an async call to a main actor function, the remaining part of the detached task is performed on the main thread, like in this example:

 Task.detached {
    print("before", Thread.isMainThread)
    await self.test()
    print("after", Thread.isMainThread)
}

@MainActor
func test() async {
    print("inside", Thread.isMainThread)
}

which leads to the following console output:

before false
inside true
after true

I reduced this example from our real-world application project in which such a detached computational task is blocking the UI/main thread.

Interestingly, the problem does not occur if you slightly modify the code by removing the async qualifier of the test function like this:

@MainActor 
func test() {
    print("inside", Thread.isMainThread)
}

Then the the following console output appears:

before false
inside true
after false

The problem also disappears if you wrap the main actor access inside a separate task like this:

func test() async {
    let task = Task { @MainActor in
        print("inside", Thread.isMainThread)
    }
    await task.value
}

This also leads to the following console output:

before false
inside true
after false

I am currently puzzled by the behaviour of the first variant and consider it a bug which I also filed under FB10022919. I also created a demo Xcode project showing the problem.

I would be very happy if anybody from this forum could shed some light on what is going on here.

2 Likes

This may be related to the behavior described in SE-0338. @John_McCall did this ship in a release yet?

1 Like

I believe that should be fixed in the latest Xcode as part of SE-0338, yes.

1 Like

Sorry, just to be clear. This shipped as part of Swift 5.6 in Xcode 13.3 and 13.4, correct? Was there a runtime element that limits the fix to just iOS 15.4 (and macOS 12.3, etc.) and later? Or is rebuilding with newer Xcode enough?

1 Like

It just requires a rebuild, not any runtime change.

Which Xcode version do you mean? For me, the main thread blocking error still occurs with Xcode 13.4 on macOS 12.4.