Re: Spinning the busy indicator
Re: Spinning the busy indicator
- Subject: Re: Spinning the busy indicator
- From: Graham Cox <email@hidden>
- Date: Fri, 01 May 2015 12:15:08 +1000
> On 1 May 2015, at 10:18 am, Quincey Morris <email@hidden> wrote:
>
> On Apr 30, 2015, at 16:39 , Graham Cox <email@hidden> wrote:
>>
>> As I mentioned it’s the spinning busy indicator, which is always indeterminate.
>
> The circular style isn’t always indeterminate, though (I forgot) it looks different when it’s not indeterminate.
Well, the docs say:
> This method only has an effect if style returns NSProgressIndicatorBarStyle. If style returns NSProgressIndicatorSpinningStyle, the indicator is always indeterminate, regardless of what you pass to this method.
However, I’m now fairly convinced that this is a red herring, and is a side effect of the more serious bug.
>
> My app also hits a breakpoint at _dispatch_semaphore_wait_slow when I click on a menu bar menu, also in the middle of talking to another process via XPC, so I don’t think that’s a cause of your problem.
>
> Instead, I suspect you have a memory management error that’s corrupting something. Or a thread safety error that’s causing this as a side effect.
I’m starting to think that as well.
I’m using ARC - I keep trying to get on board with ARC, and every time I do I seem to run into this sort of difficult to track down issue. At this stage I’ll try and persist with it, because I’m not getting any problems when I use any of the memory managment debugging aids such as zombies and guard malloc, etc. So perhaps as you suggest it’s more of a thread safety issue. I can well believe it could be, as I’m just exploring using NSOperationQueue for this kind of processing, and maybe I’ve just done it wrong.
The app here is only an experiment - if I can get it to work properly it’ll be useful experience that I can apply to other situations. So I’m drawing a portion of the Mandelbrot set in a view. I tile the view into a number of tiles and each one is given the appropriate coordinates and goes away and does the calculation work in a block added to an NSOperationQueue. Plotting the Mandelbrot set is a good experiment because it is eminently parallisable without any co-dependencies between tiles - it just needs to keep track of which part of the overall view it belongs to.
When the calculation for a tile is finished, it calls its delegate to tell it it has finished. The delegate is the original view. I use -performSelectorOnMainThread: to notify the delegate. In response, it takes a bitmap that the tile created and filled in, and draws it in the view (well, it’s a little more complex. When the delegate of the tile gets the ‘finished’ notification, it adds the tile to a dictionary of tiles that can be drawn, keyed by a string version of the tile’s coordinates, then it calls -setNeedsDisplayInRect: for that tile. When -drawRect is called, it iterates through the dictionary drawing tiles that intersect the dirty region of the view.) That all works fine - as each tile completes, I see the view plot that tile, so gradually the view fills with the complete image.
Pursuing the corruption/thread safety angle, if I set it to just use 1 tile for the view, all is well. The spinner spins and the menubar doesn’t block. If I go to 2x2 tiles, it’s still OK. Any more than that and the menubar click blocks the main thread and the spinner doesn’t animate. Thus the problem is sensitive to the number of tasks I add to the NSOperationQueue.
The code that schedules the work is:
if( !self.busy )
{
mBusy = YES;
[[[self class] mandelGeneratorQueue] addOperationWithBlock:^
{
[self createBitmapIfNeeded];
if([self.delegate respondsToSelector:@selector(mandelGeneratorWillStartCalculation:)])
[self.delegate performSelectorOnMainThread:@selector(mandelGeneratorWillStartCalculation:) withObject:self waitUntilDone:NO];
NSUInteger x, y, xm, ym;
size_t index;
NSRect dr = self.destinationRect;
x = xm = NSWidth( dr );
y = ym = NSHeight( dr );
while( y-- )
{
x = xm;
while( x-- )
{
CGFloat ev = [self calculateEscapeValueAtX:x y:y];
[self plotEscapeValue:ev atX:x y:y];
}
}
mBusy = NO;
if([self.delegate respondsToSelector:@selector(mandelGeneratorDidFinishCalculation:)])
[self.delegate performSelectorOnMainThread:@selector(mandelGeneratorDidFinishCalculation:) withObject:self waitUntilDone:NO];
}];
}
If I replace the work done in the inner loop with usleep( 10 ), I still see the same problem, so whatever the cause of the issue it isn’t a fault with the actual Mandelbrot calculation, but with the whole tile plotting on a thread architecture.
Stumped.
—GRaham
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden