Hmm, that is interesting! I wonder if we are misreporting the thread ID or something. Could you print out the thread ID in the main queue and on the run method?
I'm not sure it is just about reporting. When ParsableCommand (not async) is used, Thread.isMainThread gives expected result. Another issue with MainActor and RunLoop.main lead me to this issue SDL, game loop and Swift Concurrency - #3 by Eugene_Gubin
How to get it on Windows? Debug descripton gives <Thread: 0x000002806581dba0>
Okay, so then it sounds like what we are treating as the main thread and the thread that the application spins up on and the main queue runs on are possibly different. This is definitely odd. I do know that we do some trickery with CF to attempt to detect the "main thread":
_NS_pthread_main_np aka pthread_main_np should be invoked on the main thread as that is invoked from __CFInitialize indirectly through __CFWindowsExecutableInitializer which should be invoked on the main thread in the executable as it is a module ctor, which should be executed early enough that there should be no other thread executing that code.
For what it's worth "main actor" does not always mean "main thread", would you mind doing a MainActor.preconditionIsolated() and make sure you're in Swift 6 mode? That'd be interesting to see what is reported.
Package.swift starts with swift-tools-version: 6.0
@main
struct EntryPoint3: AsyncParsableCommand {
@MainActor
mutating func run() async throws {
print("Thread is main: \(Thread.isMainThread)")
print("Current Thread ID: \(GetCurrentThreadId())")
MainActor.preconditionIsolated()
await withCheckedContinuation { con in
DispatchQueue.main.async {
print("Thread is main (queue): \(Thread.isMainThread)")
print("Current Thread ID (queue): \(GetCurrentThreadId())")
MainActor.preconditionIsolated()
con.resume()
}
}
print("completed")
}
}
Output:
Thread is main: false
Current Thread ID: 498188
Thread is main (queue): false
Current Thread ID (queue): 498188
completed
I thinks it is fine on Apple platforms where people usually use DispatchQueue which too does not always mean "main thread". But how to use aforementioned SDL which explicitly tells you to use some entities from main thread only because underlying platform API is designed that way?
Does "main actor" bound to a single thread, or to a thread pool?
Currently all the "big" platforms (apple, linux, windows) enqueue work to underlying dispatch queue. And that implementation is swift-corelibs-dispatch, on linux and windows. Main actor work is just submitted to the "main dispatch queue".
So whatever behavior about threads/queues is unexpected on windows will be an issue in swift-corelibs-dispatch itself.
By the above snippet not crashing (thanks for confirming!) it's for sure true that the runtime determines that queue is the main actor, otherwise precondition would have crashed.
We are interested in exploring non-dispatch runtimes, but today that's the state of the world.
@compnerd is it expected behavior? Should I start another thread about DispatchQueue.main is not bound to main thread or report an issue in corelibs-dispatch?
We already have two threads about the same question kind of so let's keep it in this one.
About dispatch's behavior being expected or not here... I don't know -- @rokhinip or @compnerd are folks who might now if it is by design that dispatch's main queue on windows is not the main thread?