Reputation: 47739
I have an app that tends to do a lot of DB activity in a background thread (downloading large database updates), and quite often this process "starves" the UI thread -- I know that the DB is being released at intervals, but the @synchronized
mechanism that is used is not "fair" and allows the background thread to immediately reacquire the lock.
Is there another mechanism that is reasonably efficient and well-supported (and not too hard to retrofit) (and "fair") that could be used instead?
Upvotes: 1
Views: 418
Reputation: 55583
I cannot reproduce your issue. Here I have a simple program (albeit running on mac), based on @synchronized
and pthreads, which clearly shows that @synchronized
works as expected, assuming you release your locks:
void *backgroundThread(void *data)
{
while (true)
{
@synchronized (globalMutex)
{
usleep(USEC_PER_SEC / 3);
}
}
return NULL;
}
int main()
{
pthread_t bgThread = NULL;
globalMutex = [NSObject new];
pthread_create(&bgThread, NULL, &backgroundThread, NULL);
NSTimeInterval lastTime = [[NSDate date] timeIntervalSinceReferenceDate];
while (true)
{
@synchronized (globalMutex)
{
NSTimeInterval elapsed = [[NSDate date] timeIntervalSinceReferenceDate] - lastTime;
NSLog(@"Main Thread 'came up for air' after %lf seconds", elapsed);
lastTime += elapsed;
}
}
}
Output:
TestProj[1494:303] Main Thread 'came up for air' after 0.000015 seconds TestProj[1494:303] Main Thread 'came up for air' after 0.003136 seconds TestProj[1494:303] Main Thread 'came up for air' after 0.000637 seconds TestProj[1494:303] Main Thread 'came up for air' after 0.000610 seconds TestProj[1494:303] Main Thread 'came up for air' after 0.000697 seconds TestProj[1494:303] Main Thread 'came up for air' after 0.000576 seconds TestProj[1494:303] Main Thread 'came up for air' after 0.000571 seconds TestProj[1494:303] Main Thread 'came up for air' after 0.337343 seconds TestProj[1494:303] Main Thread 'came up for air' after 0.335533 seconds TestProj[1494:303] Main Thread 'came up for air' after 0.335253 seconds TestProj[1494:303] Main Thread 'came up for air' after 0.335309 seconds TestProj[1494:303] Main Thread 'came up for air' after 0.335367 seconds TestProj[1494:303] Main Thread 'came up for air' after 0.335223 seconds TestProj[1494:303] Main Thread 'came up for air' after 0.335754 seconds TestProj[1494:303] Main Thread 'came up for air' after 0.335271 seconds TestProj[1494:303] Main Thread 'came up for air' after 0.335211 seconds TestProj[1494:303] Main Thread 'came up for air' after 0.334555 seconds TestProj[1494:303] Main Thread 'came up for air' after 0.335245 seconds TestProj[1494:303] Main Thread 'came up for air' after 0.335203 seconds TestProj[1494:303] Main Thread 'came up for air' after 0.335262 seconds TestProj[1494:303] Main Thread 'came up for air' after 0.335252 seconds TestProj[1494:303] Main Thread 'came up for air' after 0.335667 seconds TestProj[1494:303] Main Thread 'came up for air' after 0.335278 seconds TestProj[1494:303] Main Thread 'came up for air' after 0.335309 seconds
So unless you aren't properly releasing your locks, @synchronized
is exactly what you need in this scenario. Please elaborate on what your synchronization code actually looks like, so that we can help you more.
Upvotes: 2
Reputation: 1936
If you are worried about blocking your UI thread, you could create a serial dispatch queue for your database operations. This would enable you to queue up some DB operation from the UI thread, without blocking it (the block of work will just be copied to the heap, stored until its turn to be processed).
For example, from the UI thread, you could:
database_queue = dispatch_queue_create("com.example.queue", NULL);
dispatch_async(database_queue, ^{
// Operations on the DB here
});
// The UI will continue responding immediately after here...
The queue will process each block one at a time, providing the synchronisation that you need - you just need to make sure all DB operations are done from that one queue.
If you do need to wait until the work has indeed been done, you can swap out the async call for a sync call in those particular instances:
dispatch_sync(database_queue, ^{
....
....
Upvotes: 0
Reputation: 23288
As I underestand @synchronized is a convenient way to create mutex locks. It doesn't have to be "fair".
I would recommend to read about GCD. It has a lot of interesting stuff to put all the work which needs to be done in queues (which should provide better resource sharing).
Upvotes: 1