-
Notifications
You must be signed in to change notification settings - Fork 10.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[SR-14802] Concurrency: Unstructured Task Triggering Continuation Can Hang #57150
Comments
@swift-ci create |
This seems to have regressed further in beta 2. Now none of my awaited work seems to complete unless I put a `print` statement in the `request` method before returning the `DataRequest` value. The `print` at the end of `didComplete` is still necessary if the continuations are resumed within an unstructured task. |
This is still an issue in beta 3. A print statement in the request method is required for any of the work to start. |
For information. I'm still seeing failures with this test case in Xcode beta 5 (running on iPhone Simulator): import XCTest
@available(iOS 15.0, macOS 12.0, *)
actor SUTActor {
var continuation: CheckedContinuation<(),Never>?
var canGo = false
func pause() async {
print("in pause")
if canGo {
print("canGo true before awat")
return
}
await withCheckedContinuation { (continuation: CheckedContinuation<Void, Never>) -> Void in
print("in withCheckedContinuation operation")
if canGo {
print("canGo true after awit")
Task.detached { continuation.resume() }
} else {
self.continuation = continuation
}
print("completing withCheckedOperation closure")
}
print("awaitedContinuation resumed")
}
func go() {
print("in go")
canGo = true
let continuation = self.continuation
print(continuation == nil ? "nil cont" : "has cont")
self.continuation = nil
Task.detached {
print("resuming continuation")
continuation?.resume()
print("did resume continuation")
}
}
}
@available(iOS 15.0, macOS 12.0, *)
final class ActorContinuationTests : XCTestCase {
func testPauseGo() {
let sut = SUTActor()
let exp = expectation(description: "Will resume")
Task.detached(priority: .high) {
print("will await pause")
await sut.pause()
print("pause returned")
exp.fulfill()
}
Task.detached(priority: .medium) {
print("will await go")
await sut.go()
print("Boom")
}
waitForExpectations(timeout: 0.3, handler: nil)
_ = sut // Ensure lifetime sufficient
}
} A failed run prints:
So it seems that it never actually enters the `go()` function. When it works it seems that the withCheckedContinuationClosure is completed before go is awaited. This may actually be more related to the issue in release notes "Swift tasks won't have their priority escalated in response to awaiting on their handles. (76127623)" although I don't think there needs to be any escalation. The issue does seem dependent on the different priorities and other test cases seem to now be working. As before with my test cases this doesn't fail every time but does fail a few times in every hundred. |
Hmm, this should've been fixed in beta 5. The change that was made was that all priorities get "squashed" to the unspecified level (because the smarter scheduling that took priorities into account wasn't working) so high vs low priority shouldn't matter. I'll double-check on whether the change landed in time for beta 5 or not. |
Looks like not all the patches landed in beta 5, in particular this one: #38709 @josephlord In the meantime, if you do not specify priorities, does the issue go away or are you still seeing the issue without explicit priorities? |
Yes. I can’t reproduce without the priorities. It isn’t blocking anything for me. Just wanted to report results of re-running my exploratory test cases. |
Attachment: Download
Environment
Xcode 13b1, default and 6/14 5.5 toolchain, iOS 15 simulator
Additional Detail from JIRA
md5: 299292dc9504c5fcebe4846384790ce5
is duplicated by:
Issue Description:
As discussed on the forums: https://forums.swift.org/t/concurrency-hang-when-continuations-resumed-in-task-but-not-in-actor/49772/6
I create a continuation to allow users to wait for network data captured by an actor and capture its resume in a stored closure. When that capture is complete, I call the enqueued closures to trigger the continuations. Strictly calling the closure within an actor method works fine. Wrapping the closure call in an unstructured task causes a hang and the waiter is never notified. However, simply adding a print statement at the end of the actor method allows it to work. My test iOS project is attached.
The text was updated successfully, but these errors were encountered: