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
keep NSBundle calls on a single thread #1970
Conversation
instead of locking self also, protect the resourceDict
Looks good. You're right that Since you're not |
NSString *path = [[NSBundle bundleWithPath:gSysIconBundle] pathForResource:name ofType:@"icns"]; | ||
__block NSString *path; | ||
QSGCDQueueSync(resourceQueue, ^{ | ||
path = [[NSBundle bundleWithPath:gSysIconBundle] pathForResource:name ofType:@"icns"]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, we probably don’t need to wrap the places where the NSBundle
object is a local variable only. How could another thread send it a message in that case?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NSBundle
is not thread safe so we do need to ensure that any calls we make to NSBundle are always on the same thread.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any calls to the same object though, right? As it says in the link…
Many objects deemed “thread-unsafe” are only unsafe to use from multiple threads. Many of these objects can be used from any thread as long as it is only one thread at a time. Objects that are specifically restricted to the main thread of an application are called out as such.
So a local variable that gets destroyed as soon as the method finishes should be safe on any thread.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not quite sure what you mean by local variable - path
?
The variable
in this case is the singleton NSBundle
.
I'd imagine that +[NSBundle bundleWithPath:]
looks something like this:
+(NSBundle *)bundleWithPath:(NSString *)path {
NSDictionary static *bundlesDict = [NSMutableDictionary dictionary];
if ([bundlesDict objectForKey:path]) {
return [bundlesDict objectForKey:path];
}
NSBundle *b = [NSBundle _somePrivateMethodToGetBundle:path];
[bundlesDict setObject:b forKey:path];
return b;
}
and it's because of this set/get that it may not be thread safe. Looking at it now, I think you're referring to the NSBundle instance, I'm referring to the NSBundle
shared instance. If you call [NSBundle bundeWithPath:]
from multiple different threads at the same time, the same NSBundle object will be returned.
As always, Mike Ash has something on the subject :) (I think his referring to 'usage on the main thread only' was before GCD came about)
Yes, I meant the instance returned by
If that’s true, then the code is probably fine as is. At least in this one class. We should probably have |
So, when you say “soonish”… 😉 |
Hey, we do things slowly in Wales alright? :P Looking over it again, I'm slightly worried that this could cause deadlocks, but I have no grounds for that. Just seeing We'll see ;-) |
keep NSBundle calls on a single thread
Well, I hope not. The way I picture it in my head, previously you had everyone coming in from multiple directions at the same time. Now, everyone has to get in line and go in, then out, the same way. I could be wrong, but people have reported it fixing the existing hangs. |
…in
QSResourceManager
I think @pjrobertson was right in #1861 when he said these calls should be on a single thread. But the actual code in #1871 didn’t keep it on one thread. It just locked
QSRez
so multiple threads couldn’t make changes simultaneously. We should probably avoid locking frequently used singletons likeQSRez
unless absolutely necessary.I’ve attempted to change this so it queues things up on a single thread instead of locking the object. It seems to prevent the freezes people are reporting.
There aren’t as many changes as it looks like. It’s mostly indentation changes for things that aren’t wrapped in
@synchronized
any more.fixes #1957