最近我遇到了一个问题,我需要一些代码块来同时在主线程上执行。可以从任何线程调用此块。我使用此SO answer by @Brad Larson
中已建议的代码解决了此问题作为对这个答案的评论很明显可能发生死锁,但我很容易陷入僵局。请看一下这段代码。
-(IBAction) buttonClicked
{
// Dispatch on the global concurrent queue async.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
NSString* data = [self getTheString];
NSLog(@"From Background Thread: %@", data);
};
// Dispatch on the main queue async.
dispatch_async(dispatch_get_main_queue(), ^{
NSString* data = [self getTheString];
NSLog(@"From Main Thread: %@", data);
};
}
// This method can be called from any thread so synchronize it.
// Also the code that sets the string variable based on some logic need to execute on main thread.
-(NSString*) getTheString
{
__block NSString* data = nil;
@synchronized(self)
{
// Have some code here that need to be synchronized between threads.
// .......
//
// Create a block to be executed on the main thread.
void (^blockToBeRunOnMainThread)(void) = ^{
// This is just a sample.
// Determining the actual string value can be more complex.
data = @"Tarun";
};
[self dispatchOnMainThreadSynchronously:blockToBeRunOnMainThread];
}
}
- (void) dispatchOnMainThreadSynchronously:(void(^)(void))block
{
if([NSThread isMainThread])
{
if (block)
{
block();
}
}
else
{
dispatch_sync(dispatch_get_main_queue(), ^{
if (block)
{
block();
}
});
}
}
在这段代码中,有两个同时发出异步请求来运行getTheString(假设您无法控制buttonClicked方法以及它如何调用getTheString api )。假设来自全局队列的请求是第一个并且它试图同步在主线程上运行块,直到那个时候后台线程在等待主线程同步执行块,同时来自主队列的请求来到并尝试从后台线程获取锁,但作为后台线程在不完整的主线程中等待后台线程完成。 这里我们在主线程上有一个死锁,作为主线程等待后台线程完成,后台线程正在等待主线程执行块。
如果删除@synchronize语句,一切正常。可能我在这里不需要@synchronize语句,但在同样的情况下你可能需要这个。或者甚至可以从代码的其他部分发生。
我试图在整个网络中搜索解决方案,并尝试了dispatch_semaphore但无法解决问题。可能是我没有以正确的方式做事。
我认为这是经典的死锁问题,并且一次又一次地被开发人员所面对,并且可能已经在某种程度上解决了它。任何人都可以帮忙解决这个问题,还是指向正确的方向?
答案 0 :(得分:1)
我会创建一个同步队列(NSOperationQueue
最简单)并将要在主线程上运行的块提交到该队列。队列将按接收的顺序分配块,保持您想要的顺序。同时,它解除了调用getTheString
方法和调度到主线程之间的同步性。