Concurrency

RSS for tag

Concurrency is the notion of multiple things happening at the same time.

Posts under Concurrency tag

102 Posts
Sort by:

Post

Replies

Boosts

Views

Activity

Swift 5.10: Cannot access property '*' with a non-sendable type '*' from non-isolated deinit; this is an error in Swift 6
The following Swift UIKit code produces the warning "Cannot access property 'authController' with a non-sendable type 'AuthController' from non-isolated deinit; this is an error in Swift 6": import UIKit class AuthFormNavC: UINavigationController { let authController: AuthController init(authController: AuthController) { self.authController = authController super.init(rootViewController: ConsentVC()) } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } deinit { authController.signInAnonymouslyIfNecessary() } } Swift 5.10, Xcode 15.3 with complete strict concurrency checking. What is the workaround? Please don't ask me why I'm doing what I'm doing or anything unrelated to the question. If you're wondering why I want to call authController.signInAnonymouslyIfNecessary() when the navigation controller is denitialized, my goal is to call it when the navigation controller is dismissed (or popped), and I think that the deinitializer of a view controller is the only method that is called if and only if the view controller is being dismissed (or popped) in my case. I tried observing variables like isViewLoaded in the past using KVO but I couldn't get it to work passing any combination of options in observe(_:options:changeHandler:).
1
0
471
Apr ’24
How to resolve SwiftUI.DynamicProperty on MainActor compiler warning on 6.0?
Hi! I'm running into a warning from a SwiftUI.DynamicProperty on a 6.0 development build (swift-6.0-DEVELOPMENT-SNAPSHOT-2024-03-26-a). I am attempting to build a type (conforming to DynamicProperty) that should also be MainActor. This type with also need a custom update function. Here is a simple custom wrapper (handwaving over the orthogonal missing pieces) that shows the warning: import SwiftUI @MainActor struct MainProperty: DynamicProperty { // Main actor-isolated instance method 'update()' cannot be used to satisfy nonisolated protocol requirement; this is an error in the Swift 6 language mode @MainActor func update() { } } Is there anything I can do about that warning? Does the warning correctly imply that this will be a legit compiler error when 6.0 ships? I can find (at least) two examples of types adopting DynamicProperty from Apple that are also MainActor: FetchRequest and SectionedFetchRequest. What is confusing is that both FetchRequest^1 and SectionedFetchRequest^2 explicitly declare their update method to be MainActor. Is there anything missing from my Wrapper declaration that can get me what I'm looking for? Any more advice about that? Thanks!
3
0
396
2h
How to make sysctl and gettimeofday thread-safe in Swift?
I am trying to sync the ntp time from the server using Kronos library. However, I believe the code is not fully protected from multithreading access since it is using low level system code. So, does anyone know how can I ensure sysctl and gettimeofday are thread-safe when calling them? Or, is there any thread-safe alternative to get the same result? func currentTime() -> TimeInterval { var current = timeval() let systemTimeError = gettimeofday(&current, nil) != 0 assert(!systemTimeError, "system clock error: system time unavailable") return Double(current.tv_sec) + Double(current.tv_usec) / 1_000_000 } static func systemUptime() -> TimeInterval { var mib = [CTL_KERN, KERN_BOOTTIME] var size = MemoryLayout<timeval>.stride var bootTime = timeval() let bootTimeError = sysctl(&mib, u_int(mib.count), &bootTime, &size, nil, 0) != 0 assert(!bootTimeError, "system clock error: kernel boot time unavailable") let now = currentTime() let uptime = Double(bootTime.tv_sec) + Double(bootTime.tv_usec) / 1_000_000 assert(now >= uptime, "inconsistent clock state: system time precedes boot time") return now - uptime } I have thought of using NSLock but I can only protect from the getter (caller) not the setter (system)
14
0
581
May ’24
Cannot convert value of type 'any Error'
I have an async function where im using the withUnsafeContinuation method and closure but for some reason Xcode is not letting me pass either 'error' or 'Error' for continuation.resume(throwing:). I get the error "Cannot convert value of type 'any Error'" public func parseResponseData(data: Data) async throws -> TextResult { return try await withUnsafeContinuation { continuation in Task { do { let decoder = JSONDecoder() let result = try await decoder.decode(TextResult.self, from: data) continuation.resume(returning: result) } catch { continuation.resume(throwing: error) } } } }
1
0
402
Mar ’24
Handle multiple AsyncThrowingStreams in structured concurrency?
Hello, im currently rewriting my entire network stuff to swift concurrency. I have a Swift Package which contains the NWConnection with my custom framing protocol. So Network framework does not support itself concurrency so I build an api around that. To receive messages I used an AsyncThrowingStream and it works like that: let connection = MyNetworkFramework(host: "example.org") Task { await connection.start() for try await result in connection.receive() { // do something with result } } that's pretty neat and I like it a lot but now things got tricky. in my application I have up to 10 different tcp streams I open up to handle connection stuff. so with my api change every tcp connection runs in it's own task like above and I have no idea how to handle the possible errors from the .receive() func inside the tasks. First my idea was to use a ThrowingTaskGroup for that and I think that will work but biggest problem is that I initially start with let's say 4 tcp connections and I need the ability to add additional ones later if I need them. so it seems not possible to add a Task afterwards to the ThrowingTaskGroup. So what's a good way to handle a case like that? i have an actor which handles everything in it's isolated context and basically I just need let the start func throw if any of the Tasks throw I open up. Here is a basic sample of how it's structured. Thanks Vinz internal actor MultiConnector { internal var count: Int { connections.count } private var connections: [ConnectionsModel] = [] private let host: String private let port: UInt16 private let parameters: NWParameters internal init(host: String, port: UInt16, parameters: NWParameters) { self.host = host self.port = port self.parameters = parameters } internal func start(count: Int) async throws -> Void { guard connections.isEmpty else { return } guard count > .zero else { return } try await sockets(from: count) } internal func cancel() -> Void { guard !connections.isEmpty else { return } for connection in connections { connection.connection.cancel() } connections.removeAll() } internal func sockets(from count: Int) async throws -> Void { while connections.count < count { try await connect() } } } // MARK: - Private API - private extension MultiConnector { private func connect() async throws -> Void { let uuid = UUID(), connection = MyNetworkFramework(host: host, port: port, parameters: parameters) connections.append(.init(id: uuid, connection: connection)) let task = Task { [weak self] in guard let self else { return }; try await stream(connection: connection, id: uuid) } try await connection.start(); await connection.send(message: "Sample Message") // try await task.value <-- this does not work because stream runs infinite until i cancel it (that's expected and intended but it need to handle if the stream throws an error) } private func stream(connection: MyNetworkFramework, id: UUID) async throws -> Void { for try await result in connection.receive() { if case .message(_) = result { await connection.send(message: "Sample Message") } // ... more to handle } } }
3
0
602
Mar ’24
Swift concurrency and NSData - all threads stuck in mach_msg2_trap
I run the following code in an actor: func aaa() async throws -> Data { async let result = Task( operation: { ... decompressing data through try (data as NSData).decompressed(using: .lzfse) as Data } ).result switch await result { case .success(let value): return value case .failure(let error): throw error } I do it this way because I do not want to block the actor by decompression, and there is no state change in the actor afterwards. I would say that the actor plays no significant role here. Important is that many (14) concurrent tasks run in parallel, however NOT on the same data. It runs fine for a while (dozens/hundreds of data decompressed), and then the following happens: Activity Monitor (macOS GUI tool) shows almost none User CPU time, and approx. 75% System CPU time. The rest is idle. (When it runs fine, User CPU time is 95+%) When I pause the run in Xcode (in release config it behaves the same), all threads are in mach_msg2_trap #0 0x0000000180ac21f4 in mach_msg2_trap () #1 0x0000000180ad4b24 in mach_msg2_internal () #2 0x0000000180ac52fc in vm_copy () #3 0x0000000180916b78 in szone_realloc () #4 0x000000018093cfb0 in _malloc_zone_realloc () #5 0x000000018093d7e8 in _realloc () #6 0x0000000180bb8a10 in __CFSafelyReallocate () #7 0x0000000181d00e30 in _NSMutableDataGrowBytes () #8 0x0000000181ce2630 in -[NSConcreteMutableData appendBytes:length:] () #9 0x00000001823c30d8 in -[_NSDataCompressor processBytes:size:flags:] () #10 0x00000001823c32c4 in -[NSData(NSDataCompression) _produceDataWithCompressionOperation:algorithm:handler:] () #11 0x00000001823c3598 in -[NSData(NSDataCompression) _decompressedDataUsingCompressionAlgorithm:error:] () It looks like something is wrong with safe reallocation, however if this have been a bug, then all macOS is stuck. Any idea, please?
2
0
582
Mar ’24
Task in @MainActor Function Appears to Become Detached
I'm hoping someone can help me understand some unexpected behavior in a @MainActor Function which internally calls a task that calls a method on a background actor. Normally, the function would call the task, pause until the task completes, and finish the end of the function. However, when the function is annotated @Main actor, the internal task appears to become detached and execute asynchronously such that it finishes after the @MainActor function. The code below demonstrates this behavior in a playground: actor SeparateActor{ func actorFunc(_ str:String){ print("\tActorFunc(\(str))") } } class MyClass{ var sa = SeparateActor() @MainActor func mainActorFunctionWithTask(){ print("mainActorFunctionWithTask Start") Task{ await self.sa.actorFunc("mainActorFunctionWithTask") } print("mainActorFunctionWithTask End") } func normalFuncWithTask(){ print("normalFuncWithTask Start") Task{ await self.sa.actorFunc("normalFuncWithTask") } print("normalFuncWithTask End") } } Task{ let mc = MyClass() print("\nCalling normalFuncWithTask") mc.normalFuncWithTask() print("\nCalling mainActorFunctionWithTask") await mc.mainActorFunctionWithTask() } I would expect both the normalFunc and the mainActorFunc to behave the same, with the ActorFunc being called before the end of the task, but instead, my mainActor function completes before the task. Calling normalFuncWithTask normalFuncWithTask Start ActorFunc(normalFuncWithTask) normalFuncWithTask End Calling mainActorFunctionWithTask mainActorFunctionWithTask Start mainActorFunctionWithTask End ActorFunc(mainActorFunctionWithTask)
2
0
554
Mar ’24
Swift 5.9 Noncopyable and os_unfair_lock crash
Hello, I recently implemented a lock that uses OSAllocatedUnfairLock on iOS 16+ and os_unfair_lock on below iOS 16. I know that using os_unfair_lock with Swift is tricky, and it is error-prone. For example, the famous open-source library Alamofire has even been using os_unfair_lock incorrectly in terms of Swift's lifecycle view. (They fixed it as in the link [1] ) So, I implemented a lock like below. To use os_unfair_lock safely, I used the Noncopyable protocol which was added in Swift 5.9 [2]. Also, I allocated memory on the heap to use os_unfair_lock. public struct UnfairLock: ~Copyable { public init() { if #available(iOS 16.0, *) { _osAllocatedUnfairLock = OSAllocatedUnfairLock() } else { self.unfairLock = UnsafeMutablePointer.allocate(capacity: 1) } } deinit { if #unavailable(iOS 16.0) { unfairLock!.deallocate() } } public func lock() { if #available(iOS 16.0, *) { osAllocatedUnfairLock.lock() } else { os_unfair_lock_lock(unfairLock!) } } public func unlock() { if #available(iOS 16.0, *) { osAllocatedUnfairLock.unlock() } else { os_unfair_lock_unlock(unfairLock!) } } public func with<T>(_ closure: () -> T) -> T { lock() defer { unlock() } return closure() } private var _osAllocatedUnfairLock: Any? private var unfairLock: UnsafeMutablePointer<os_unfair_lock_s>? @available(iOS 16.0, *) private var osAllocatedUnfairLock: OSAllocatedUnfairLock<Void> { // swiftlint:disable force_cast _osAllocatedUnfairLock as! OSAllocatedUnfairLock // swiftlint:enable force_cast } } However, I got several crashes on iOS 14-15 users like this (This app targets iOS 14+ and on iOS 16+, it uses OSAllocatedUnfairLock): (Sorry for using a third-party crash reporting tool's log, but I think it is enough to understand the issue) BUG IN CLIENT OF LIBPLATFORM: os_unfair_lock is corrupt Crashed: com.foo.bar.queue 0 libsystem_platform.dylib 0x6144 _os_unfair_lock_corruption_abort + 88 1 libsystem_platform.dylib 0xa20 _os_unfair_lock_lock_slow + 320 2 FoooBarr 0x159416c closure #1 in static FooBar.baz() + 6321360 3 FoooBarr 0x2e65b8 thunk for @escaping @callee_guaranteed @Sendable () -> () + 4298794424 (<compiler-generated>:4298794424) 4 libdispatch.dylib 0x1c04 _dispatch_call_block_and_release + 32 5 libdispatch.dylib 0x3950 _dispatch_client_callout + 20 6 libdispatch.dylib 0x6e04 _dispatch_continuation_pop + 504 7 libdispatch.dylib 0x6460 _dispatch_async_redirect_invoke + 596 8 libdispatch.dylib 0x14f48 _dispatch_root_queue_drain + 388 9 libdispatch.dylib 0x15768 _dispatch_worker_thread2 + 164 10 libsystem_pthread.dylib 0x1174 _pthread_wqthread + 228 11 libsystem_pthread.dylib 0xf50 start_wqthread + 8 ( libplatform's source code [3] suggests that __ulock_wait returns error, but I don't know the details) Per @eskimo 's suggestion in [4], I will change my code to use NSLock until OSAllocatedUnfairLock is available on all users' devices (i.e. iOS 16+), but I still want to know why this crash happens. I believe that making a struct Noncopyable is enough to use os_unfair_lock safely, but it seems that it is not enough. Did I miss something? Or is there any other way to use os_unfair_lock safely? [1] https://github.com/Alamofire/Alamofire/commit/1b89a57c2f272408b84d20132a2ed6628e95d3e2 [2] https://github.com/apple/swift-evolution/blob/1b0b339bc3072a83b5a6a529ae405a0f076c7d5d/proposals/0390-noncopyable-structs-and-enums.md [3] https://github.com/apple-open-source/macos/blob/ea4cd5a06831aca49e33df829d2976d6de5316ec/libplatform/src/os/lock.c#L555 [4] https://forums.developer.apple.com/forums/thread/712379
1
0
371
Mar ’24
Xcode 15.3 and iOS 17.4 generate a CPU spike when launching the app
I've just updated to Xcode 15.3 and iOS 17.4 (simulator). Every time I launch the app, I see a CPU spike keeping the CPU at 100% for about 30 seconds on a background thread. After those 30 seconds, there's a 'Thread Performance Checker' error posted on the console. This does not happen when using Xcode 15.2 and running on iOS 17.2. or iOS 16.4. Thread Performance Checker: Thread running at User-initiated quality-of-service class waiting on a thread without a QoS class specified (base priority 33). Investigate ways to avoid priority inversions PID: 70633, TID: 2132693 Backtrace ================================================================= 3 CFNetwork 0x000000018454094c estimatedPropertyListSize + 28648 4 CFNetwork 0x00000001843d7fc0 cfnTranslateCFError + 1864 5 libdispatch.dylib 0x000000010557173c _dispatch_client_callout + 16 6 libdispatch.dylib 0x0000000105573210 _dispatch_once_callout + 84 7 CFNetwork 0x00000001843d7f8c cfnTranslateCFError + 1812 8 CFNetwork 0x0000000184540814 estimatedPropertyListSize + 28336 9 libdispatch.dylib 0x000000010557173c _dispatch_client_callout + 16 10 libdispatch.dylib 0x0000000105573210 _dispatch_once_callout + 84 11 CFNetwork 0x0000000184540728 estimatedPropertyListSize + 28100 12 CFNetwork 0x0000000184540794 estimatedPropertyListSize + 28208 13 libdispatch.dylib 0x000000010557173c _dispatch_client_callout + 16 14 libdispatch.dylib 0x0000000105573210 _dispatch_once_callout + 84 15 CFNetwork 0x0000000184540780 estimatedPropertyListSize + 28188 16 CFNetwork 0x00000001844e8664 _CFNetworkHTTPConnectionCacheSetLimit + 191584 17 CFNetwork 0x00000001844e78dc _CFNetworkHTTPConnectionCacheSetLimit + 188120 18 CFNetwork 0x000000018439ce5c _CFURLCachePersistMemoryToDiskNow + 25460 19 CFNetwork 0x0000000184483068 _CFStreamErrorFromCFError + 609680 20 CFNetwork 0x000000018445105c _CFStreamErrorFromCFError + 404868 21 CFNetwork 0x000000018443a040 _CFStreamErrorFromCFError + 310632 22 CFNetwork 0x000000018453be14 estimatedPropertyListSize + 9392 23 CFNetwork 0x000000018440fa5c _CFStreamErrorFromCFError + 137092 26 CFNetwork 0x000000018445b398 _CFStreamErrorFromCFError + 446656 27 CFNetwork 0x0000000184459db8 _CFStreamErrorFromCFError + 441056 28 CFNetwork 0x000000018445cf60 _CFStreamErrorFromCFError + 453768 29 CFNetwork 0x0000000184541838 estimatedPropertyListSize + 32468 30 libdispatch.dylib 0x000000010556fec4 _dispatch_call_block_and_release + 24 31 libdispatch.dylib 0x000000010557173c _dispatch_client_callout + 16 32 libdispatch.dylib 0x0000000105579a30 _dispatch_lane_serial_drain + 916 33 libdispatch.dylib 0x000000010557a774 _dispatch_lane_invoke + 420 34 libdispatch.dylib 0x000000010557b6e4 _dispatch_workloop_invoke + 864 35 libdispatch.dylib 0x00000001055871a8 _dispatch_root_queue_drain_deferred_wlh + 324 36 libdispatch.dylib 0x0000000105586604 _dispatch_workloop_worker_thread + 488 37 libsystem_pthread.dylib 0x0000000106b87924 _pthread_wqthread + 284 38 libsystem_pthread.dylib 0x0000000106b866e4 start_wqthread + 8
11
6
6.9k
Apr ’24
Is OSLog Logger Sendable?
The new Xcode 15.3 Release Candidate produces errors with strict concurrency checking that the usual pattern of using OSLog with a static property like static let logger = Logger(...) is not safe. "Static property 'logger' is not concurrency-safe because it is not either conforming to 'Sendable' or isolated to a global actor; this is an error in Swift 6" Is Logger thread safe and just not marked Sendable? Would it be "safe" to use nonisolated(unsafe) static let logger = Logger(...)?
2
2
1.9k
Mar ’24
NSLock broken when using optimize speed in XCode Swift?
Dear Sirs, I've written a SwiftUI application in XCode where I'm using multiple threads which are synchronized by using NSLock and NSRecursiveLock. This works in Debug mode and in Release mode as long as I don't use the Swift Compiler - Code Generation -&gt; Optimization Level -O for "Optimize for Speed". This is unfortunately the default setting but it results in multiple threads accessing the same piece of code which is encapsulated inside a NSLock. Is this an intended behaviour? Thanks and best regards, Johannes
6
0
632
Mar ’24
Is it possible to introspect QoS overrides via a debugger?
I was wondering if there is a way, while debugging, to observe the 'QoS boosting' behavior that is implemented in various places to provide priority inversion avoidance. The pthread_override_qos_class_start/end_np header comments specifically say that overrides aren't reflected in the qos_class_self() and pthread_get_qos_class_np() return values. As far as I can tell the 'CPU Report' UI in Xcode also does not reflect this information (perhaps for the reason the header comments call out). Is there a direct mechanism to observe this behavior? Presumably a heuristic empirical test could be done to compare throughput of a queue that should have its priority boosted and one that should not, but I would prefer a less opaque means of verification if possible. Thanks in advance!
3
0
695
Feb ’24
Heavy Duty Work With Async Await
I am perplexed as to how to use async await. In the following example, I don't use GCD or performSelector(inBackground:with:). The view controller is NSViewController, but it doesn't make any difference if it's NSViewController or UIViewController. import Cocoa class ViewController: NSViewController { func startWriteImages() { Task{ let bool = await startWriteImagesNext() if bool { print("I'm done!") } } } func startWriteImagesNext() async -&gt; Bool { // pictures is a path to a folder in the sandbox folder // appDelegate.defaultFileManager is a variable pointing to FileManager.default in AppDelegate let pictURL = URL(fileURLWithPath: pictures) if let filePaths = try? self.appDelegate.defaultFileManager.contentsOfDirectory(atPath: pictURL.path) { for file in filePaths { let fileURL = pictURL.appending(component: file) if self.appDelegate.defaultFileManager.fileExists(atPath: fileURL.path) { let newURL = self.folderURL.appending(component: file) do { try self.appDelegate.defaultFileManager.copyItem(at: fileURL, to: newURL) } catch { print("Ugghhh...") } } } return true } return false } func startWriteImagesNext2() async -&gt; Bool { let pictURL = URL(fileURLWithPath: pictures) if let filePaths = try? self.appDelegate.defaultFileManager.contentsOfDirectory(atPath: pictURL.path) { DispatchQueue.global().async() { for file in filePaths { let fileURL = pictURL.appending(component: file) if self.appDelegate.defaultFileManager.fileExists(atPath: fileURL.path) { let newURL = self.folderURL.appending(component: file) do { try self.appDelegate.defaultFileManager.copyItem(at: fileURL, to: newURL) } catch { print("Ugghhh...") } } } } return true } return false } } In the code above, I'm saving each file in the folder to user-selected folder (self.folderURL). And the application will execute the print guy only when work is done. Since it's heavy-duty work, I want to use CCD or performSelector(inBackground:with:). If I use the former (startWriteImagesNext2), the application will execute the print guy right at the beginning. I suppose I cannot use GCD with async. So how can I perform heavy-duty work? Muchos thankos.
4
0
745
Feb ’24
Looking for tutorial on how to use SwiftData correctly in background threads
Hello community, I am in search of a tutorial that comprehensively explains the proper utilization of SwiftData for updating model data in a background thread. From my understanding, there is extensive coverage on creating a model and loading model data into a view, likely due to Apple's detailed presentation on this aspect of SwiftData during WWDC23. Nevertheless, I am encountering difficulties in finding a complete tutorial that addresses the correct usage of SwiftData for model updates in a background thread. While searching the web, I came across a few discussions on Stack Overflow and this forum that potentially provide an approach. However, they were either incomplete or proved ineffective in practical application. I would greatly appreciate any links to tutorials that thoroughly cover this topic.
1
0
1.1k
Feb ’24
Can macOS dynamically change QoS value for pthreads
I have observed that in my application, Even If I set the QoS value of all the thread created to USER_INTERACTIVE, the OS is producing a warning "Thread running at User-Interactive QoS class waiting on a lower QoS thread running at Default QoS class. Investigate ways to avoid priority inversions". I am aware that it is not right to set all threads as USER_INTERACTIVE QoS, but If we assume this case for once, then it means that the OS can dynamically change the QoS of the threads even if we are explicitly setting it. Is this the correct understanding? Also, the main thread has QoS value USER_INTERACTIVE, then is it the case that its child threads will inherit the QoS value from the parent thread, If we are not setting any QoS for a pthread?
1
2
655
Jan ’24