Dispatch

RSS for tag

Execute code concurrently on multicore hardware by submitting work to dispatch queues managed by the system using Dispatch.

Posts under Dispatch tag

113 Posts

Post

Replies

Boosts

Views

Activity

WWDC 2015 video on GCD missing (again)
In a thread titled “Avoid Dispatch Global Concurrent Queues” [1], Quinn links to a video from WWDC 2015 Session 718, “Building Responsive and Efficient Apps with GCD”. However, this video is not available from the Apple Developer Videos site; only a half dozen or so videos from 2015 are available. This same issue of the missing video came up about five years ago, when Quinn stated that the video had been mistakenly removed but had been restored. Now it’s gone again. :sad_face: Could this video be restored again, or at least its transcript? While I understand that Apple is focused on Swift concurrency, I need to maintain some Objective-C code that uses GCD, and in tracking down some performance issues, I would like to better understand the tradeoffs in the existing code and make improvements where I can. I don’t have the resources to reimplement the code in Swift right now. (More generally, why can't Apple just leave all these videos online indefinitely, for historical purposes at least? Couldn't the ones deemed “old and misleading” just be tagged with a banner like the legacy documentation has?) [1] I like to think of these valuable threads as “Quinn Technical Notes”; I have a page in my Notes app that holds links to the ones I’ve found.
5
1
1.4k
Sep ’23
dispatch_once weird behavior
Hi! I have a xcode workspace with first objectiveC framework (let’s call it framework#1). This framework has some singletons (+(instancetype)shared using the dispatch_once idiom. This code is pretty straight forward and used everywhere : + (instancetype)shared { static dispatch_once_t onceToken; static OGAKeyManager *instance = nil; dispatch_once(&onceToken, ^{ instance = [[self alloc] init]; }); return instance; } I have a second framework (framework#2) in Swift that uses theses singletons (the framework#1 is added as do not embeed in the framework settings). And I have an application that uses both frameworks. If I make a breakpoint inside the dispatch_once alloc/init, I see that I enter 2 times : once when the shared method is called from framework#1 and another one when it’s called from framework#2. How is that even possible ? Isn't dispatch_once supposed to handle this ? I asked chatGPT, it points out to some objC/Swift interoperability, but honestly, I don't see what I can do to make it work correctly. There is no circular dependency (framwork#2 uses framwork#1, but framwork#1 has no clue of framwork#2 existence) Maybe it has something to do with sandbox, but I don't see how can it be. Does anyone experienced some weird behavior like this ? Thanks
7
0
1.6k
Sep ’23
Crash at _dispatch_client_callout + 28, no my code on stack trace
I had 2 crash report from our customer. Both crash point is same but there is no my code on crash stack trace. How to fix this kind of crash problem. Thread 1 Crashed:: Dispatch queue: com.apple.root.background-qos 0 libsystem_kernel.dylib 0x7ff81b84922a __pthread_kill + 10 1 libsystem_pthread.dylib 0x7ff81b880f7b pthread_kill + 263 2 libsystem_c.dylib 0x7ff81b7caca5 abort + 123 3 libc++abi.dylib 0x7ff81b83b082 abort_message + 241 4 libc++abi.dylib 0x7ff81b82c23d demangling_terminate_handler() + 266 5 libobjc.A.dylib 0x7ff81b529023 _objc_terminate() + 96 6 libc++abi.dylib 0x7ff81b83a4a5 std::__terminate(void (*)()) + 8 7 libc++abi.dylib 0x7ff81b83a456 std::terminate() + 54 8 libdispatch.dylib 0x7ff81b701a58 _dispatch_client_callout + 28 9 libdispatch.dylib 0x7ff81b704500 _dispatch_continuation_pop + 463 10 libdispatch.dylib 0x7ff81b715dff _dispatch_source_invoke + 2184 11 libdispatch.dylib 0x7ff81b7116a2 _dispatch_root_queue_drain + 343 12 libdispatch.dylib 0x7ff81b711e4d _dispatch_worker_thread2 + 160 13 libsystem_pthread.dylib 0x7ff81b87dc9d _pthread_wqthread + 256 14 libsystem_pthread.dylib 0x7ff81b87cc67 start_wqthread + 15 This crash point is exactly same with this post. I do not throw C++ exception. https://developer.apple.com/forums/thread/725197
4
0
2.5k
Jul ’23
Thread QOS class
I see this warning when my app runs: Thread running at QOS_CLASS_USER_INTERACTIVE waiting on a lower QoS thread running at QOS_CLASS_DEFAULT. Investigate ways to avoid priority inversions This is true; I know what is going on. I'd like this other thread to have a higher priority. But how do I set the "QOS class" for a thread? Searching developer.apple.com for QOS_CLASS_USER_INTERACTIVE doesn't find much. It seems that dispatch queues have priorities, but in this case I have a thread, not a dispatch queue. Any ideas?
8
0
5.7k
Jul ’23
memory race on deep looper
Below is some simple code that does nothing, saves nothing. Yet the memory usage keeps rising. Am I missing something or is this a bug? The code requires 6 core CPU minimum. ContentView.swift import SwiftUI import Combine struct ContentView: View { @EnvironmentObject var loopClass:LoopClass var body: some View { ProgressView(value: Float(loopClass.loop_count), total: Float(loopClass.max_loops) ).progressViewStyle(.circular).padding() Button("Run looper", action: { loopClass.loopFunc() } ) } } LoopClass.swift import Combine class LoopClass: ObservableObject { @Published var loop_count = 0 @Published var max_loops = 0 func loopFunc () { let loopSet = [ 1, 3, 5, 7, 11, 13 ] max_loops = Int(pow(Double(loopSet.count), 13.0)) print("max_loops = \(max_loops)") for loop13 in loopSet { DispatchQueue.global().async { for loop12 in loopSet { for loop11 in loopSet { for loop10 in loopSet { for loop9 in loopSet { for loop8 in loopSet { for loop17 in loopSet { for loop16 in loopSet { for loop5 in loopSet { for loop4 in loopSet { for loop3 in loopSet { for loop2 in loopSet { for loop1 in loopSet { DispatchQueue.main.async{ self.loop_count += 1 } } }}}}}}}}}}} } // DQ } // for loop13 } }
2
0
1k
Jul ’23
Call actor-isolated function backed by a DispatchSerialQueue using DispatchSerialQueue.async
In What's New In Swift, a new DispatchSerialQueue-backed actor was introduced. We're able to call MainActor-annotated functions using DispatchQueue.main.async without errors or warnings. For example: @MainActor func randomFunc() { print("Hello World") } DispatchQueue.main.async { randomFunc() } However calling a globalActor-annotated function or a regular actor-isolated function backed by a DispatchSerialQueue, we get the warning Actor-isolated instance method 'randomFunc()' can not be referenced from a non-isolated context; this is an error in Swift 6. Code here: actor MyActor { private let queue: DispatchSerialQueue nonisolated var unownedExecutor: UnownedSerialExecutor { queue.asUnownedSerialExecutor() } init(queue: DispatchSerialQueue) { self.queue = queue } func randomFunc() { print("Hello World!") } } let queue = DispatchSerialQueue(label: "actorQueue") let actor = MyActor(queue: queue) queue.async { actor.randomFunc() // Warning here } Although it has a warning, the code still runs successfully and prints Hello World, but it would also do so from another DispatchQueue not used by the actor (this was tested in Version 15.0 beta (15A5160n) Playground). My question: Can we remove the warning resulting from calling an actor isolated function backed by DispatchSerialQueue A using A.async { }, if that's safe behavior? If it's not safe, why not?
0
0
2k
Jun ’23
How do the run loop of the main thread and the main queue are related?
Do run loops use an operation queue under the hood? When I dispatch to the mian queue, I know it will run on the mian thread, which means it will be handled b the main thread's run loop. But is the other way around correct? More specific question, is it possible somehow that the following code will return true? OperationQueue.current != OperationQueue.main && Thread.isMainThread I tried to do for example to dispatch to the main thread using a timer. myQueue.sync { let timer = Timer(timeInterval: 1, repeats: false) { _ in let curr = OperationQueue.current let main = OperationQueue.main print("\(String(describing: curr)) \(main)") } RunLoop.main.add(timer, forMode: .common) } And got the same pointer. But maybe some other way of dispatching to the main run loop will give different results, possibly that is why OperationQueue.current can return nil.
1
0
2.2k
May ’23
Crash: Unbalanced call to dispatch_group_leave()
Experiencing an increased amount of crash reports with the latest release of the app. I've spent some time online understanding the meaning of Unbalanced call to dispatch_group_leave() however, I am struggling to pinpoint what's the source of the problem inside the codebase. I wish you can help me with these crash logs. Will calling a closure from inside CoreData context's perform() will eventually result into this crash and cause leave() to get called multiple times? The main code was there for long time, the only recent change was to wrap some code around CoreData context perform() or performAndWait() to avoid concurrency issues. 2023-05-20_10-42-03.5467_+0100-e8b3d9b142b8fd3d11c72abc01ad2fbcfbe92aee.crash 2023-05-22_20-57-32.2620_+0400-5d4c76afe1e42937cf09035d3034fb33ec40f0c9.crash 2023-05-21_19-36-18.3480_+0100-c01f62a2b78cae616c6202940f06220b7ea3b760.crash 2023-05-16_15-29-43.3962_+0100-ebb44a6156a3771271acfdd459546fe1271eb370.crash
1
0
1.4k
May ’23
Design pattern for scheduling simulation steps
I'm running a simulation (SwiftUI app), which has 100 steps. I need each step to be executed in order. A first try was to dispatch with delay to schedule each second: for step in 0..<100 { DispatchQueue.main.asyncAfter(deadline: .now() + Double(step) * 1.0) { // simulation code } } Very poor results as 100 running threads are too much load for the system. So I split in 2 stages: for bigStep in 0..<10 { DispatchQueue.main.asyncAfter(deadline: .now() + Double(bigStep) * 10.0 ) { for step in 0..<10 { DispatchQueue.main.asyncAfter(deadline: .now() + Double(step) * 1.0) { // simulation code } } } } It works much better, as now there are a max of 20 threads active (in fact I create more levels to limit to a max of 8 concurrent threads). It addition, it allows to interrupt the simulation before end. My questions: is it the appropriate pattern ? Would a timer be better ? Other options ?
4
0
1.3k
May ’23
Safe to update SKSpriteNode's texture on background thread?
I understand UI updates have to be on the main thread, but what about SKSpriteNode's texture? Can I update that in the background? I can update it in the background and it works like I want it to. No crashes, warnings, etc. I did verify that the thread is not the main thread via [NSThread isMainThread]. I have since wrapped the texture change in a dispatch_sync on the main queue and it works the same as without it. Regards, Patrick
0
0
950
May ’23
Stack buffer overflow error using JSONDecoder
I'm using JSONDecoder().decode(T.Type, from: data) to decode a JSON response from a server. It works in some cases but eventually my program crashes with the error "Stack buffer overflow". The size of the JSON data I'm trying to decide is about 16k, which is large, but not unusually so. The decode is happening in a non-main thread, but I tried pushing it into the main thread with the same results. Most of these crashes occur in the simulator rather than on a real device, but I'd like to figure out the problem anyway. I thought I'd try dispatching the work into a queue with a larger stack size, but I couldn't figure out how to make one. Is it possible? Thanks, Frank
1
0
1.1k
May ’23
dispatch_async to global much slower in recent Mac Catalyst versions?
has anyone else noticed much slower GCD runs in newer MacOS / Catalyst this seems like it used to be blazing fast: dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INTERACTIVE, 0), ^{ // code to run }); now if I run a block on this type of queue versus the main thread, the dispatched code runs much slower vs main thread. not 10%, like multiple slower. i am not sure yet if it is the code run time or time for dispatch to trigger. trying to focus in on what is the problem on our side and get some metrics, but if anyone has seen this issue, it might be useful to compare notes.
3
0
1.4k
May ’23
_dispatch_assert_queue_fail under iOS 16.4.1. Don't understand the error.
Since updating to iOS 16.4.1, our app crashes randomly with the following error message. Exception Codes: 0x0000000000000001, 0x0000000199d542c0 Termination Reason: SIGNAL 5 Trace/BPT trap: 5 Terminating Process: exc handler [499] Triggered by Thread: 2 Thread 2 Crashed: 0 libdispatch.dylib 0x199d542c0 _dispatch_assert_queue_fail + 120 1 libdispatch.dylib 0x199d54248 dispatch_assert_queue + 196 2 UIKitCore 0x1949c870c -[UIImageView _mainQ_beginLoadingIfApplicable] + 88 3 UIKitCore 0x19495db34 -[UIImageView setHidden:] + 68 4 UIKitCore 0x19492f128 -[UIButtonLegacyVisualProvider _updateImageView] + 372 5 UIKitCore 0x19492ed78 -[UIButtonLegacyVisualProvider layoutSubviews] + 116 6 UIKitCore 0x19492ecc4 -[UIButton layoutSubviews] + 40 7 UIKitCore 0x1948fbef4 -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 1920 8 QuartzCore 0x193db64ac CA::Layer::layout_if_needed(CA::Transaction*) + 500 9 QuartzCore 0x193dc9a28 CA::Layer::layout_and_display_if_needed(CA::Transaction*) + 148 10 QuartzCore 0x193ddae54 CA::Context::commit_transaction(CA::Transaction*, double, double*) + 444 11 QuartzCore 0x193e0a3c0 CA::Transaction::commit() + 648 12 QuartzCore 0x193e54b08 CA::Transaction::release_thread(void*) + 228 13 libsystem_pthread.dylib 0x1f2214b9c _pthread_tsd_cleanup + 620 14 libsystem_pthread.dylib 0x1f2217560 _pthread_exit + 84 15 libsystem_pthread.dylib 0x1f22140cc _pthread_wqthread_exit + 80 16 libsystem_pthread.dylib 0x1f2213e64 _pthread_wqthread + 424 17 libsystem_pthread.dylib 0x1f2213b7c start_wqthread + 8 I have trouble interpreting where our error lies within the exception. Can anyone give me a hint as to what kind of problem this might be? Kind regards
6
0
3.4k
May ’23
iOS App Crash on Touch?
Hi guys new to iOS dev here and encountered a strange crash that hope you guys can help with. Background: The app is built using React-Native, with the @fkyskywhy/react-native-gcanvas library. Main logic was to draw images on a canvas via WebGL API (provided by gcanvas) Issue Symptoms: When testing the app on an actual device via TestFlight, it usually crashes the app upon launch, and randomly thereafter. After repeated testing I was able to recreate the crash when debugging on actual device by repeatedly tapping the screen. When testing the app on in simulator, I could not reproduce the crash at all. Also if the device is hooked up to the MacBook while testing, I also couldn't reproduce the crash the same way. When it crashed, this is what I could gather from the crash log: Exception Type: EXC_BAD_ACCESS (SIGSEGV) Exception Subtype: KERN_INVALID_ADDRESS at 0x0000000000000000 Exception Codes: 0x0000000000000001, 0x0000000000000000 VM Region Info: 0 is not in any region. Bytes before following region: 4299587584 REGION TYPE START - END [ VSIZE] PRT/MAX SHRMOD REGION DETAIL UNUSED SPACE AT START ---&gt; __TEXT 100468000-10119c000 [ 13.2M] r-x/r-x SM=COW ...pp/mobileGame Termination Reason: SIGNAL 11 Segmentation fault: 11 Terminating Process: exc handler [16911] Triggered by Thread: 9 Every time it crashes, it would be trigger by a different thread, I assume is based on how the cpu schedules it. In this particular case, the stack of thread 9 are as below: Thread 9 name: Dispatch queue: OpenGLMT Thread 9 Crashed: 0 ??? 0x0 ??? 1 libdispatch.dylib 0x1c5a05eac _dispatch_client_callout + 20 2 libdispatch.dylib 0x1c5a0d534 _dispatch_lane_serial_drain + 668 3 libdispatch.dylib 0x1c5a0e0a4 _dispatch_lane_invoke + 384 4 libdispatch.dylib 0x1c5a18cdc _dispatch_workloop_worker_thread + 648 5 libsystem_pthread.dylib 0x21dec7ddc _pthread_wqthread + 288 6 libsystem_pthread.dylib 0x21dec7b7c start_wqthread + 8 Note: I noticed that the stack looked the same across all my crashes. However, I don't see any link to my code here so not sure how to start troubleshooting this issue. Any help is much appreciated!
1
0
1.1k
Apr ’23
Crash when app moved to background while some work proccessing on own queue
Hello. I found a bit strange behaviour in app. My app using linphone library for in app calls, also, app have addressbook contacts sync flow ( to add contacts from addressbook to app DB ). I found strange behaviour: if I accept call and after that move app to background while contacts sync flow is processing on own queue with QoS less than default, after ~10 seconds app crashed and deattach from debug ( without any error ) also, firebase crashlytics doesn't catch this crash, but, If I process contact sync flow on queue that have QoS default or high, there is no any crash and all going well. Could please anyone explain this behavior?
7
0
3.1k
Apr ’23
AVAudioConverter buffers are over-retained in a DispatchQueue.concurrentPerform context
I have an audio analysis tool which I’m trying to parallelise, but it uses an escalating amount of heap space when working on a set of audio files. It turns out that when I use the convert(to:error:withInputFrom:) method of AVAudioConverter inside a concurrentPerform block, a large amount of the memory associated with each conversion is retained until the very end of the concurrent performance, rather than being released at the end of each iteration’s execution. As such, the memory usage climbs and climbs while a batch of files is processed, rather than staying effectively flat during parallel operations. I’m assuming that this is some flaw in my code rather than a bug in either framework, and hope someone can help me find it. See below a simplified version of the code, which converts the same file an arbitrary number of times (rather than operating on a large batch of different files as is the case in my real application). Any help appreciated! let outputFormat = AVAudioFormat(commonFormat: .pcmFormatFloat32, sampleRate: 8000, channels: 1, interleaved: false)! DispatchQueue.global(qos: .userInitiated).async { DispatchQueue.concurrentPerform(iterations: 1000) { index in let inputFile = try! AVAudioFile(forReading: URL(filePath: "/path/to/some/song.m4a")) let inputFormat = inputFile.processingFormat let inputFrameCount = AVAudioFrameCount(inputFile.length) let inputBuffer = AVAudioPCMBuffer(pcmFormat: inputFormat, frameCapacity: inputFrameCount)! try! inputFile.read(into: inputBuffer) let sampleRateCoefficient = inputFormat.sampleRate / outputFormat.sampleRate let outputFrameCount = UInt32(Double(inputFrameCount) / sampleRateCoefficient) let outputBuffer = AVAudioPCMBuffer(pcmFormat: outputFormat, frameCapacity: outputFrameCount)! let converter = AVAudioConverter(from: inputBuffer.format, to: outputFormat)! let converterInputBlock: AVAudioConverterInputBlock = { _, outStatus in outStatus.pointee = AVAudioConverterInputStatus.haveData return inputBuffer } // If we just do some arbitrary work here, even big mallocs, memory usage is flat as everything is released at the end of the concurrentPerform closure. // But if we run this conversion, each iteration retains a big chunk of memory until they're all finished. :( converter.convert( to: outputBuffer, error: nil, withInputFrom: converterInputBlock ) } }
2
0
1.2k
Apr ’23
If C static buffer exceed 249440 bytes, dispatch async get EXC_BAD_ACCESS code=2 on Intel simulator
Not too hopeful that anyone can explain this but here is goes. I have some C code being used from an iOS app in Swift. Logs in the C code are passed by a callback to Swift and put on a serial queue using: Log.serialQueue.async {} So, the C function could look like: int do_some_c_stuff(void) { log("Do some logging"); } And in Swift we have something like this to process the log that came through the callback: class func log(_ message: String, logInfo: LogInfo = appLogInfo, type: OSLogType = .default) { Log.serialQueue.async { os.os_log("%@", log: logInfo.log, type: type, message) } } This works perfectly in all cases except one (Intel iPhone simulator only). Now, some C functions allocate a static buffer to parse incoming messages. Like this: int do_some_c_stuff(void) { log("Do some logging"); char buf[100000]; } and here is the interesting part. If this buffer exceeds exactly 249440 bytes, any call to Log.serialQueue.async in the swift layer gets a EXC_BAD_ACCESS code=2 but only when running on Intel simulator. Running on device or M1 simulator works just fine. So on the Intel simulator this will crash calling Log.serialQueue.async: int do_some_c_stuff(void) { log("Do some logging"); // This will trigger the callback inside log which ends up in the swift layer. char buf[249441]; // buffer exceeds 249440 bytes } Also note that it is the presence of this allocation that causes issues on Intel, returning before the allocation does not help, if the allocation is present in the C function, the call to Log.serialQueue.async crash. Further, it is not the logging in the swift layer that causes the problem, simply calling Log.serialQueue.async without anything inside crashes. So, the example below still crash on Intel when accessing the serialQueue.async so I assume the large memory chunk is allocated when the function is "created", not when the buf variable is instantiated. int do_some_c_stuff(void) { log("Do some logging"); return 0; char buf[249441]; } It only happens in the Intel simulator and only in Debug mode. It is 100% reproducible in various places in the codebase, all of them using C functions that declare a local buffer larger than 249440 bytes. I do not have a minimal example at this time, hoping that someone might have an idea on why it happens but if someone is interested, maybe I can whip something up. In general, just having the C function allocate this large block and from the same function callback to swift and use dispatch.async should do the trick. Is there some sort of memory swapping, paging etc that would cause problems in a scenario like this mixing C and dispatchqueue (on intel only)? Since the solution is to reduce the stack allocation or use heap memory, this is not critical. However, if anyone knows why this is happening on Intel CPU's it would be super interesting to know.
5
0
1.1k
Mar ’23
BUG IN CLIENT OF LIBDISPATCH
There is a bug of libdispatch on my APP, which is similar to this post, but it's on iOS across versions from 13.x to 16.x. Now I downloaded the opensource code of libdispatch from here, and I want to look into the details of source code to figure out the root cause. How can I know the branch or commit of the libdispatch code the specific iOS version (like 15.6.1) uses. crash_info_0 BUG IN CLIENT OF LIBDISPATCH: Unexpected EV_VANISHED (do not destroy random mach ports or file descriptors) fault_address 0x0000000001a37b9bc4 mach_code 0x000000000000000001 mach_subcode 0x0000000001a37b9bc4 name EXC_BREAKPOINT (SIGTRAP) reason EXC_BREAKPOINT EXC_ARM_BREAKPOINT fault_address:0x00000001a37b9bc4 type MACH_Exception 0 libdispatch.dylib __dispatch_source_merge_evt.cold.1 (in libdispatch.dylib) +36 1 libdispatch.dylib __dispatch_source_merge_evt (in libdispatch.dylib) +192 2 libdispatch.dylib __dispatch_event_loop_merge (in libdispatch.dylib) +144 3 libdispatch.dylib __dispatch_workloop_worker_thread (in libdispatch.dylib) +392 4 libsystem_pthread.dylib __pthread_wqthread (in libsystem_pthread.dylib) +284 5 libsystem_pthread.dylib _start_wqthread (in libsystem_pthread.dylib) +4 By the way, what's the difference between "__dispatch_source_merge_evt.cold.1" and "__dispatch_source_merge_evt"
1
0
3.7k
Nov ’22
Getting the current queue and thread name?
The Xcode console logs an identifier indicating the current thread that's running when a message is print()ed from Swift. Some more complex logging systems (e.g. swift-log and console-kit) don't provide that information, and I'm trying to write a logging back-end for swift-log that will. Thing is, I don't see any way to get the current queue name in Swift. I tried dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL) But I get "cannot convert value of type '()' to expected argument type 'DispatchQueue?'". Passing nil instead results in "'dispatch_queue_get_label' has been replaced by property 'DispatchQueue.label'". This is not an unreasonable thing to want to do, and it poses no safety concerns.
4
0
5.7k
Nov ’22
WWDC 2015 video on GCD missing (again)
In a thread titled “Avoid Dispatch Global Concurrent Queues” [1], Quinn links to a video from WWDC 2015 Session 718, “Building Responsive and Efficient Apps with GCD”. However, this video is not available from the Apple Developer Videos site; only a half dozen or so videos from 2015 are available. This same issue of the missing video came up about five years ago, when Quinn stated that the video had been mistakenly removed but had been restored. Now it’s gone again. :sad_face: Could this video be restored again, or at least its transcript? While I understand that Apple is focused on Swift concurrency, I need to maintain some Objective-C code that uses GCD, and in tracking down some performance issues, I would like to better understand the tradeoffs in the existing code and make improvements where I can. I don’t have the resources to reimplement the code in Swift right now. (More generally, why can't Apple just leave all these videos online indefinitely, for historical purposes at least? Couldn't the ones deemed “old and misleading” just be tagged with a banner like the legacy documentation has?) [1] I like to think of these valuable threads as “Quinn Technical Notes”; I have a page in my Notes app that holds links to the ones I’ve found.
Replies
5
Boosts
1
Views
1.4k
Activity
Sep ’23
dispatch_once weird behavior
Hi! I have a xcode workspace with first objectiveC framework (let’s call it framework#1). This framework has some singletons (+(instancetype)shared using the dispatch_once idiom. This code is pretty straight forward and used everywhere : + (instancetype)shared { static dispatch_once_t onceToken; static OGAKeyManager *instance = nil; dispatch_once(&onceToken, ^{ instance = [[self alloc] init]; }); return instance; } I have a second framework (framework#2) in Swift that uses theses singletons (the framework#1 is added as do not embeed in the framework settings). And I have an application that uses both frameworks. If I make a breakpoint inside the dispatch_once alloc/init, I see that I enter 2 times : once when the shared method is called from framework#1 and another one when it’s called from framework#2. How is that even possible ? Isn't dispatch_once supposed to handle this ? I asked chatGPT, it points out to some objC/Swift interoperability, but honestly, I don't see what I can do to make it work correctly. There is no circular dependency (framwork#2 uses framwork#1, but framwork#1 has no clue of framwork#2 existence) Maybe it has something to do with sandbox, but I don't see how can it be. Does anyone experienced some weird behavior like this ? Thanks
Replies
7
Boosts
0
Views
1.6k
Activity
Sep ’23
Crash at _dispatch_client_callout + 28, no my code on stack trace
I had 2 crash report from our customer. Both crash point is same but there is no my code on crash stack trace. How to fix this kind of crash problem. Thread 1 Crashed:: Dispatch queue: com.apple.root.background-qos 0 libsystem_kernel.dylib 0x7ff81b84922a __pthread_kill + 10 1 libsystem_pthread.dylib 0x7ff81b880f7b pthread_kill + 263 2 libsystem_c.dylib 0x7ff81b7caca5 abort + 123 3 libc++abi.dylib 0x7ff81b83b082 abort_message + 241 4 libc++abi.dylib 0x7ff81b82c23d demangling_terminate_handler() + 266 5 libobjc.A.dylib 0x7ff81b529023 _objc_terminate() + 96 6 libc++abi.dylib 0x7ff81b83a4a5 std::__terminate(void (*)()) + 8 7 libc++abi.dylib 0x7ff81b83a456 std::terminate() + 54 8 libdispatch.dylib 0x7ff81b701a58 _dispatch_client_callout + 28 9 libdispatch.dylib 0x7ff81b704500 _dispatch_continuation_pop + 463 10 libdispatch.dylib 0x7ff81b715dff _dispatch_source_invoke + 2184 11 libdispatch.dylib 0x7ff81b7116a2 _dispatch_root_queue_drain + 343 12 libdispatch.dylib 0x7ff81b711e4d _dispatch_worker_thread2 + 160 13 libsystem_pthread.dylib 0x7ff81b87dc9d _pthread_wqthread + 256 14 libsystem_pthread.dylib 0x7ff81b87cc67 start_wqthread + 15 This crash point is exactly same with this post. I do not throw C++ exception. https://developer.apple.com/forums/thread/725197
Replies
4
Boosts
0
Views
2.5k
Activity
Jul ’23
Thread QOS class
I see this warning when my app runs: Thread running at QOS_CLASS_USER_INTERACTIVE waiting on a lower QoS thread running at QOS_CLASS_DEFAULT. Investigate ways to avoid priority inversions This is true; I know what is going on. I'd like this other thread to have a higher priority. But how do I set the "QOS class" for a thread? Searching developer.apple.com for QOS_CLASS_USER_INTERACTIVE doesn't find much. It seems that dispatch queues have priorities, but in this case I have a thread, not a dispatch queue. Any ideas?
Replies
8
Boosts
0
Views
5.7k
Activity
Jul ’23
memory race on deep looper
Below is some simple code that does nothing, saves nothing. Yet the memory usage keeps rising. Am I missing something or is this a bug? The code requires 6 core CPU minimum. ContentView.swift import SwiftUI import Combine struct ContentView: View { @EnvironmentObject var loopClass:LoopClass var body: some View { ProgressView(value: Float(loopClass.loop_count), total: Float(loopClass.max_loops) ).progressViewStyle(.circular).padding() Button("Run looper", action: { loopClass.loopFunc() } ) } } LoopClass.swift import Combine class LoopClass: ObservableObject { @Published var loop_count = 0 @Published var max_loops = 0 func loopFunc () { let loopSet = [ 1, 3, 5, 7, 11, 13 ] max_loops = Int(pow(Double(loopSet.count), 13.0)) print("max_loops = \(max_loops)") for loop13 in loopSet { DispatchQueue.global().async { for loop12 in loopSet { for loop11 in loopSet { for loop10 in loopSet { for loop9 in loopSet { for loop8 in loopSet { for loop17 in loopSet { for loop16 in loopSet { for loop5 in loopSet { for loop4 in loopSet { for loop3 in loopSet { for loop2 in loopSet { for loop1 in loopSet { DispatchQueue.main.async{ self.loop_count += 1 } } }}}}}}}}}}} } // DQ } // for loop13 } }
Replies
2
Boosts
0
Views
1k
Activity
Jul ’23
Xcode 15 b2 Dispatch has been broken
Looks like dispatch has been broken
Replies
1
Boosts
0
Views
920
Activity
Jun ’23
Call actor-isolated function backed by a DispatchSerialQueue using DispatchSerialQueue.async
In What's New In Swift, a new DispatchSerialQueue-backed actor was introduced. We're able to call MainActor-annotated functions using DispatchQueue.main.async without errors or warnings. For example: @MainActor func randomFunc() { print("Hello World") } DispatchQueue.main.async { randomFunc() } However calling a globalActor-annotated function or a regular actor-isolated function backed by a DispatchSerialQueue, we get the warning Actor-isolated instance method 'randomFunc()' can not be referenced from a non-isolated context; this is an error in Swift 6. Code here: actor MyActor { private let queue: DispatchSerialQueue nonisolated var unownedExecutor: UnownedSerialExecutor { queue.asUnownedSerialExecutor() } init(queue: DispatchSerialQueue) { self.queue = queue } func randomFunc() { print("Hello World!") } } let queue = DispatchSerialQueue(label: "actorQueue") let actor = MyActor(queue: queue) queue.async { actor.randomFunc() // Warning here } Although it has a warning, the code still runs successfully and prints Hello World, but it would also do so from another DispatchQueue not used by the actor (this was tested in Version 15.0 beta (15A5160n) Playground). My question: Can we remove the warning resulting from calling an actor isolated function backed by DispatchSerialQueue A using A.async { }, if that's safe behavior? If it's not safe, why not?
Replies
0
Boosts
0
Views
2k
Activity
Jun ’23
How do the run loop of the main thread and the main queue are related?
Do run loops use an operation queue under the hood? When I dispatch to the mian queue, I know it will run on the mian thread, which means it will be handled b the main thread's run loop. But is the other way around correct? More specific question, is it possible somehow that the following code will return true? OperationQueue.current != OperationQueue.main && Thread.isMainThread I tried to do for example to dispatch to the main thread using a timer. myQueue.sync { let timer = Timer(timeInterval: 1, repeats: false) { _ in let curr = OperationQueue.current let main = OperationQueue.main print("\(String(describing: curr)) \(main)") } RunLoop.main.add(timer, forMode: .common) } And got the same pointer. But maybe some other way of dispatching to the main run loop will give different results, possibly that is why OperationQueue.current can return nil.
Replies
1
Boosts
0
Views
2.2k
Activity
May ’23
Crash: Unbalanced call to dispatch_group_leave()
Experiencing an increased amount of crash reports with the latest release of the app. I've spent some time online understanding the meaning of Unbalanced call to dispatch_group_leave() however, I am struggling to pinpoint what's the source of the problem inside the codebase. I wish you can help me with these crash logs. Will calling a closure from inside CoreData context's perform() will eventually result into this crash and cause leave() to get called multiple times? The main code was there for long time, the only recent change was to wrap some code around CoreData context perform() or performAndWait() to avoid concurrency issues. 2023-05-20_10-42-03.5467_+0100-e8b3d9b142b8fd3d11c72abc01ad2fbcfbe92aee.crash 2023-05-22_20-57-32.2620_+0400-5d4c76afe1e42937cf09035d3034fb33ec40f0c9.crash 2023-05-21_19-36-18.3480_+0100-c01f62a2b78cae616c6202940f06220b7ea3b760.crash 2023-05-16_15-29-43.3962_+0100-ebb44a6156a3771271acfdd459546fe1271eb370.crash
Replies
1
Boosts
0
Views
1.4k
Activity
May ’23
Design pattern for scheduling simulation steps
I'm running a simulation (SwiftUI app), which has 100 steps. I need each step to be executed in order. A first try was to dispatch with delay to schedule each second: for step in 0..<100 { DispatchQueue.main.asyncAfter(deadline: .now() + Double(step) * 1.0) { // simulation code } } Very poor results as 100 running threads are too much load for the system. So I split in 2 stages: for bigStep in 0..<10 { DispatchQueue.main.asyncAfter(deadline: .now() + Double(bigStep) * 10.0 ) { for step in 0..<10 { DispatchQueue.main.asyncAfter(deadline: .now() + Double(step) * 1.0) { // simulation code } } } } It works much better, as now there are a max of 20 threads active (in fact I create more levels to limit to a max of 8 concurrent threads). It addition, it allows to interrupt the simulation before end. My questions: is it the appropriate pattern ? Would a timer be better ? Other options ?
Replies
4
Boosts
0
Views
1.3k
Activity
May ’23
Safe to update SKSpriteNode's texture on background thread?
I understand UI updates have to be on the main thread, but what about SKSpriteNode's texture? Can I update that in the background? I can update it in the background and it works like I want it to. No crashes, warnings, etc. I did verify that the thread is not the main thread via [NSThread isMainThread]. I have since wrapped the texture change in a dispatch_sync on the main queue and it works the same as without it. Regards, Patrick
Replies
0
Boosts
0
Views
950
Activity
May ’23
Stack buffer overflow error using JSONDecoder
I'm using JSONDecoder().decode(T.Type, from: data) to decode a JSON response from a server. It works in some cases but eventually my program crashes with the error "Stack buffer overflow". The size of the JSON data I'm trying to decide is about 16k, which is large, but not unusually so. The decode is happening in a non-main thread, but I tried pushing it into the main thread with the same results. Most of these crashes occur in the simulator rather than on a real device, but I'd like to figure out the problem anyway. I thought I'd try dispatching the work into a queue with a larger stack size, but I couldn't figure out how to make one. Is it possible? Thanks, Frank
Replies
1
Boosts
0
Views
1.1k
Activity
May ’23
dispatch_async to global much slower in recent Mac Catalyst versions?
has anyone else noticed much slower GCD runs in newer MacOS / Catalyst this seems like it used to be blazing fast: dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INTERACTIVE, 0), ^{ // code to run }); now if I run a block on this type of queue versus the main thread, the dispatched code runs much slower vs main thread. not 10%, like multiple slower. i am not sure yet if it is the code run time or time for dispatch to trigger. trying to focus in on what is the problem on our side and get some metrics, but if anyone has seen this issue, it might be useful to compare notes.
Replies
3
Boosts
0
Views
1.4k
Activity
May ’23
_dispatch_assert_queue_fail under iOS 16.4.1. Don't understand the error.
Since updating to iOS 16.4.1, our app crashes randomly with the following error message. Exception Codes: 0x0000000000000001, 0x0000000199d542c0 Termination Reason: SIGNAL 5 Trace/BPT trap: 5 Terminating Process: exc handler [499] Triggered by Thread: 2 Thread 2 Crashed: 0 libdispatch.dylib 0x199d542c0 _dispatch_assert_queue_fail + 120 1 libdispatch.dylib 0x199d54248 dispatch_assert_queue + 196 2 UIKitCore 0x1949c870c -[UIImageView _mainQ_beginLoadingIfApplicable] + 88 3 UIKitCore 0x19495db34 -[UIImageView setHidden:] + 68 4 UIKitCore 0x19492f128 -[UIButtonLegacyVisualProvider _updateImageView] + 372 5 UIKitCore 0x19492ed78 -[UIButtonLegacyVisualProvider layoutSubviews] + 116 6 UIKitCore 0x19492ecc4 -[UIButton layoutSubviews] + 40 7 UIKitCore 0x1948fbef4 -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 1920 8 QuartzCore 0x193db64ac CA::Layer::layout_if_needed(CA::Transaction*) + 500 9 QuartzCore 0x193dc9a28 CA::Layer::layout_and_display_if_needed(CA::Transaction*) + 148 10 QuartzCore 0x193ddae54 CA::Context::commit_transaction(CA::Transaction*, double, double*) + 444 11 QuartzCore 0x193e0a3c0 CA::Transaction::commit() + 648 12 QuartzCore 0x193e54b08 CA::Transaction::release_thread(void*) + 228 13 libsystem_pthread.dylib 0x1f2214b9c _pthread_tsd_cleanup + 620 14 libsystem_pthread.dylib 0x1f2217560 _pthread_exit + 84 15 libsystem_pthread.dylib 0x1f22140cc _pthread_wqthread_exit + 80 16 libsystem_pthread.dylib 0x1f2213e64 _pthread_wqthread + 424 17 libsystem_pthread.dylib 0x1f2213b7c start_wqthread + 8 I have trouble interpreting where our error lies within the exception. Can anyone give me a hint as to what kind of problem this might be? Kind regards
Replies
6
Boosts
0
Views
3.4k
Activity
May ’23
iOS App Crash on Touch?
Hi guys new to iOS dev here and encountered a strange crash that hope you guys can help with. Background: The app is built using React-Native, with the @fkyskywhy/react-native-gcanvas library. Main logic was to draw images on a canvas via WebGL API (provided by gcanvas) Issue Symptoms: When testing the app on an actual device via TestFlight, it usually crashes the app upon launch, and randomly thereafter. After repeated testing I was able to recreate the crash when debugging on actual device by repeatedly tapping the screen. When testing the app on in simulator, I could not reproduce the crash at all. Also if the device is hooked up to the MacBook while testing, I also couldn't reproduce the crash the same way. When it crashed, this is what I could gather from the crash log: Exception Type: EXC_BAD_ACCESS (SIGSEGV) Exception Subtype: KERN_INVALID_ADDRESS at 0x0000000000000000 Exception Codes: 0x0000000000000001, 0x0000000000000000 VM Region Info: 0 is not in any region. Bytes before following region: 4299587584 REGION TYPE START - END [ VSIZE] PRT/MAX SHRMOD REGION DETAIL UNUSED SPACE AT START ---&gt; __TEXT 100468000-10119c000 [ 13.2M] r-x/r-x SM=COW ...pp/mobileGame Termination Reason: SIGNAL 11 Segmentation fault: 11 Terminating Process: exc handler [16911] Triggered by Thread: 9 Every time it crashes, it would be trigger by a different thread, I assume is based on how the cpu schedules it. In this particular case, the stack of thread 9 are as below: Thread 9 name: Dispatch queue: OpenGLMT Thread 9 Crashed: 0 ??? 0x0 ??? 1 libdispatch.dylib 0x1c5a05eac _dispatch_client_callout + 20 2 libdispatch.dylib 0x1c5a0d534 _dispatch_lane_serial_drain + 668 3 libdispatch.dylib 0x1c5a0e0a4 _dispatch_lane_invoke + 384 4 libdispatch.dylib 0x1c5a18cdc _dispatch_workloop_worker_thread + 648 5 libsystem_pthread.dylib 0x21dec7ddc _pthread_wqthread + 288 6 libsystem_pthread.dylib 0x21dec7b7c start_wqthread + 8 Note: I noticed that the stack looked the same across all my crashes. However, I don't see any link to my code here so not sure how to start troubleshooting this issue. Any help is much appreciated!
Replies
1
Boosts
0
Views
1.1k
Activity
Apr ’23
Crash when app moved to background while some work proccessing on own queue
Hello. I found a bit strange behaviour in app. My app using linphone library for in app calls, also, app have addressbook contacts sync flow ( to add contacts from addressbook to app DB ). I found strange behaviour: if I accept call and after that move app to background while contacts sync flow is processing on own queue with QoS less than default, after ~10 seconds app crashed and deattach from debug ( without any error ) also, firebase crashlytics doesn't catch this crash, but, If I process contact sync flow on queue that have QoS default or high, there is no any crash and all going well. Could please anyone explain this behavior?
Replies
7
Boosts
0
Views
3.1k
Activity
Apr ’23
AVAudioConverter buffers are over-retained in a DispatchQueue.concurrentPerform context
I have an audio analysis tool which I’m trying to parallelise, but it uses an escalating amount of heap space when working on a set of audio files. It turns out that when I use the convert(to:error:withInputFrom:) method of AVAudioConverter inside a concurrentPerform block, a large amount of the memory associated with each conversion is retained until the very end of the concurrent performance, rather than being released at the end of each iteration’s execution. As such, the memory usage climbs and climbs while a batch of files is processed, rather than staying effectively flat during parallel operations. I’m assuming that this is some flaw in my code rather than a bug in either framework, and hope someone can help me find it. See below a simplified version of the code, which converts the same file an arbitrary number of times (rather than operating on a large batch of different files as is the case in my real application). Any help appreciated! let outputFormat = AVAudioFormat(commonFormat: .pcmFormatFloat32, sampleRate: 8000, channels: 1, interleaved: false)! DispatchQueue.global(qos: .userInitiated).async { DispatchQueue.concurrentPerform(iterations: 1000) { index in let inputFile = try! AVAudioFile(forReading: URL(filePath: "/path/to/some/song.m4a")) let inputFormat = inputFile.processingFormat let inputFrameCount = AVAudioFrameCount(inputFile.length) let inputBuffer = AVAudioPCMBuffer(pcmFormat: inputFormat, frameCapacity: inputFrameCount)! try! inputFile.read(into: inputBuffer) let sampleRateCoefficient = inputFormat.sampleRate / outputFormat.sampleRate let outputFrameCount = UInt32(Double(inputFrameCount) / sampleRateCoefficient) let outputBuffer = AVAudioPCMBuffer(pcmFormat: outputFormat, frameCapacity: outputFrameCount)! let converter = AVAudioConverter(from: inputBuffer.format, to: outputFormat)! let converterInputBlock: AVAudioConverterInputBlock = { _, outStatus in outStatus.pointee = AVAudioConverterInputStatus.haveData return inputBuffer } // If we just do some arbitrary work here, even big mallocs, memory usage is flat as everything is released at the end of the concurrentPerform closure. // But if we run this conversion, each iteration retains a big chunk of memory until they're all finished. :( converter.convert( to: outputBuffer, error: nil, withInputFrom: converterInputBlock ) } }
Replies
2
Boosts
0
Views
1.2k
Activity
Apr ’23
If C static buffer exceed 249440 bytes, dispatch async get EXC_BAD_ACCESS code=2 on Intel simulator
Not too hopeful that anyone can explain this but here is goes. I have some C code being used from an iOS app in Swift. Logs in the C code are passed by a callback to Swift and put on a serial queue using: Log.serialQueue.async {} So, the C function could look like: int do_some_c_stuff(void) { log("Do some logging"); } And in Swift we have something like this to process the log that came through the callback: class func log(_ message: String, logInfo: LogInfo = appLogInfo, type: OSLogType = .default) { Log.serialQueue.async { os.os_log("%@", log: logInfo.log, type: type, message) } } This works perfectly in all cases except one (Intel iPhone simulator only). Now, some C functions allocate a static buffer to parse incoming messages. Like this: int do_some_c_stuff(void) { log("Do some logging"); char buf[100000]; } and here is the interesting part. If this buffer exceeds exactly 249440 bytes, any call to Log.serialQueue.async in the swift layer gets a EXC_BAD_ACCESS code=2 but only when running on Intel simulator. Running on device or M1 simulator works just fine. So on the Intel simulator this will crash calling Log.serialQueue.async: int do_some_c_stuff(void) { log("Do some logging"); // This will trigger the callback inside log which ends up in the swift layer. char buf[249441]; // buffer exceeds 249440 bytes } Also note that it is the presence of this allocation that causes issues on Intel, returning before the allocation does not help, if the allocation is present in the C function, the call to Log.serialQueue.async crash. Further, it is not the logging in the swift layer that causes the problem, simply calling Log.serialQueue.async without anything inside crashes. So, the example below still crash on Intel when accessing the serialQueue.async so I assume the large memory chunk is allocated when the function is "created", not when the buf variable is instantiated. int do_some_c_stuff(void) { log("Do some logging"); return 0; char buf[249441]; } It only happens in the Intel simulator and only in Debug mode. It is 100% reproducible in various places in the codebase, all of them using C functions that declare a local buffer larger than 249440 bytes. I do not have a minimal example at this time, hoping that someone might have an idea on why it happens but if someone is interested, maybe I can whip something up. In general, just having the C function allocate this large block and from the same function callback to swift and use dispatch.async should do the trick. Is there some sort of memory swapping, paging etc that would cause problems in a scenario like this mixing C and dispatchqueue (on intel only)? Since the solution is to reduce the stack allocation or use heap memory, this is not critical. However, if anyone knows why this is happening on Intel CPU's it would be super interesting to know.
Replies
5
Boosts
0
Views
1.1k
Activity
Mar ’23
BUG IN CLIENT OF LIBDISPATCH
There is a bug of libdispatch on my APP, which is similar to this post, but it's on iOS across versions from 13.x to 16.x. Now I downloaded the opensource code of libdispatch from here, and I want to look into the details of source code to figure out the root cause. How can I know the branch or commit of the libdispatch code the specific iOS version (like 15.6.1) uses. crash_info_0 BUG IN CLIENT OF LIBDISPATCH: Unexpected EV_VANISHED (do not destroy random mach ports or file descriptors) fault_address 0x0000000001a37b9bc4 mach_code 0x000000000000000001 mach_subcode 0x0000000001a37b9bc4 name EXC_BREAKPOINT (SIGTRAP) reason EXC_BREAKPOINT EXC_ARM_BREAKPOINT fault_address:0x00000001a37b9bc4 type MACH_Exception 0 libdispatch.dylib __dispatch_source_merge_evt.cold.1 (in libdispatch.dylib) +36 1 libdispatch.dylib __dispatch_source_merge_evt (in libdispatch.dylib) +192 2 libdispatch.dylib __dispatch_event_loop_merge (in libdispatch.dylib) +144 3 libdispatch.dylib __dispatch_workloop_worker_thread (in libdispatch.dylib) +392 4 libsystem_pthread.dylib __pthread_wqthread (in libsystem_pthread.dylib) +284 5 libsystem_pthread.dylib _start_wqthread (in libsystem_pthread.dylib) +4 By the way, what's the difference between "__dispatch_source_merge_evt.cold.1" and "__dispatch_source_merge_evt"
Replies
1
Boosts
0
Views
3.7k
Activity
Nov ’22
Getting the current queue and thread name?
The Xcode console logs an identifier indicating the current thread that's running when a message is print()ed from Swift. Some more complex logging systems (e.g. swift-log and console-kit) don't provide that information, and I'm trying to write a logging back-end for swift-log that will. Thing is, I don't see any way to get the current queue name in Swift. I tried dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL) But I get "cannot convert value of type '()' to expected argument type 'DispatchQueue?'". Passing nil instead results in "'dispatch_queue_get_label' has been replaced by property 'DispatchQueue.label'". This is not an unreasonable thing to want to do, and it poses no safety concerns.
Replies
4
Boosts
0
Views
5.7k
Activity
Nov ’22