Hi Tom, I don't have an experience with libdispatch, but I want to follow your work here and learn. Which version/port of libdispatch are you using? Are you using the one provided here https://github.com/apple/swift-corelibs-libdispatch ? Or a different port?
> On Aug 27, 2023, at 10:29 AM, Tom Sheffler <[email protected]> wrote: > > > >> Date: Tue, 22 Aug 2023 08:37:24 -0700 >> From: Tom Sheffler <[email protected]> >> To: [email protected] >> Subject: AppKit, libdispatch and 100% CPU >> Message-ID: >> <cambtmcui299u1if--r+5jrcgjsv13tgzqxxz4vf39dlce_k...@mail.gmail.com> >> Content-Type: text/plain; charset="utf-8" >> >> ... > >> In an app that creates a window with AppKit and calls >> dispatch_async(dispatch_get_main_queue, ...) I am seeing the CPU spike to >> 100% when nothing is happening. I first noticed in a small program that >> had a background queue that wanted to update the display. But I have >> managed to illustrate the issue in a very simple program here: > > > > A followup to my previous post about a use of AppKit with dispatch_async and > observing 100% CPU use. I have an easy workaround, but thought I would > report what I learned along the way. > > The use case is the situation when an operation on the non-main queue > wishes to update a GUI element. The canonical way to do this with dispatch is > > dispatch_async(dispatch_get_main_queue(), ^{ > OpThatModifiesAppKitGuiWidgets(); > }); > > However, when using this with [NSApp run], after the first call to > dispatch_async to the main queue, the CPU goes to 100%. If the call > doesn't happen at first, the CPU remains low, but then rises after the > first call. > > dispatch_after(5.0 SECONDS, non_main_queue, ^{ > dispatch_async(dispatch_get_main_queue, ^{ > OpThatModifiesAppKitGuiWidgets(); > }); > }); > > The CPU wouldn't go to 100% until after 5 seconds. > > A straightforward way to fix this is to use performSelectorOnMainThread: > instead of a dispatch to the main queue. > > [self performSelectorOnMainThread:@selector(theGuiOp:) > withObject:self > waitUntilDone:NO]; > > It's easy enough to write something like performBlockOnMainThread: so that > the code > above becomes something like this > > [self performBlockOnMainThread:^{ > OpThatModifiesAppKitGuiWidgets(); > }); > > and then I can have blocks and all is fine. The app runs well and the > CPU usage is low. Use of non-main dispatch queues for background > operations is fine too. > > What do I think is happenening? > > Inside NSSRunLoop, there are two calls to dispatch internals > > _dispatch_get_main_queue_handle_4CF() > _dispatch_main_queue_callback_4CF() > > that give a handle to wait on and the function to run when its ready. > I'm no expert in RunLoop internals, but it seems that after the first > dispatch_async(main_queue()) the handle is always ready for reading > and some sort of busy-wait is happening. Even when I have not > scheduled future events on the main_queue, it is woken up repeatedly. > > -T > > >
