Objective c 具有调度同步和调度异步的串行队列
以下从主线程调用[self goToNext]的代码对于和具有不同的调度_xxxx具有不同的结果Objective c 具有调度同步和调度异步的串行队列,objective-c,grand-central-dispatch,Objective C,Grand Central Dispatch,以下从主线程调用[self goToNext]的代码对于和具有不同的调度_xxxx具有不同的结果 dispatch\u sync&dispatch\u sync,结果为死锁 dispatch\u async&dispatch\u async,结果为空 dispatch\u sync&dispatch\u async,结果是死锁 dispatch\u async&dispatch\u sync,结果为空 - (NSString *)someString { __block NSString
- (NSString *)someString {
__block NSString *localSomeString;
dispatch_async(self.serialQueue, ^{ // dispatch_xxx <1>
if ([NSThread isMainThread]) {
NSLog(@"main thread");
} else {
NSLog(@"background thread");
}
localSomeString = @"fuck you!";
});
return localSomeString;
}
- (void)goToNext
{
dispatch_sync(self.serialQueue, ^{ // dispatch_xxx <2>
if ([NSThread isMainThread]) {
NSLog(@"main thread");
} else {
NSLog(@"background thread");
}
NSLog(@"%@", [self someString]);
});
}
-(NSString*)someString{
__块NSString*localSomeString;
dispatch\u async(self.serialQueue,^{//dispatch\u xxx
如果([NSThread isMainThread]){
NSLog(@“主线程”);
}否则{
NSLog(@“后台线程”);
}
localSomeString=@“操你妈的!”;
});
返回localSomeString;
}
-(作废)GotonNext
{
调度同步(self.serialQueue,^{//dispatch\u xxx
如果([NSThread isMainThread]){
NSLog(@“主线程”);
}否则{
NSLog(@“后台线程”);
}
NSLog(@“%@,[self someString]);
});
}
有人能解释这四个结果的原因吗在处理给定的代码块之前,对
dispatch\u async
的调用会立即返回。因此,在异步示例中,localSomeString
在初始化之前返回(NULL
)。您可以通过向方法someString
引入一个完成块作为参数来解决此问题,然后在代码块中调用该方法:
- (void)someStringWithCompletion:(void(^)(NSString* someString))completion {
dispatch_sync<2>(self.serialQueue, ^{
if ([NSThread isMainThread]) {
NSLog(@"main thread");
} else {
NSLog(@"background thread");
}
localSomeString = @"fuck you to!";
completion(localSomeString)
});
}
- (void)goToNext
{
dispatch_sync<2>(self.serialQueue, ^{
if ([NSThread isMainThread]) {
NSLog(@"main thread");
} else {
NSLog(@"background thread");
}
[self someStringWithCompletion:^(NSString *result) {
NSLog(result);
}
});
}
-(void)someStringWithCompletion:(void(^)(NSString*someString))completion{
调度同步(self.serialQueue^{
如果([NSThread isMainThread]){
NSLog(@“主线程”);
}否则{
NSLog(@“后台线程”);
}
localSomeString=@“去你的!”;
完成(localSomeString)
});
}
-(作废)GotonNext
{
调度同步(self.serialQueue^{
如果([NSThread isMainThread]){
NSLog(@“主线程”);
}否则{
NSLog(@“后台线程”);
}
[self someStringWithCompletion:^(NSString*结果){
NSLog(结果);
}
});
}
对dispatch\u sync
的调用将等待代码块被处理,从而阻止调用它的线程。因此,如果在当前使用的队列上调用dispatch\u sync
,则当前使用的队列将等待代码块完成,但代码块永远不会像在同一队列上一样执行(当前正在等待)排队。首先:您应该(重新?)阅读GCD的介绍。尝试一些选项直到其中一个运行是没有选择的,您显然是这样做的,因为这可能会在下一台机器上失败
创建一个串行队列。在串行队列中,一个块依次执行。这描述了订阅块之间的关系,而不是与调用者之间的关系
同步或异步订阅描述块与订阅块的代码之间的关系。这并不是描述块之间的关系,而是描述块与“调用者”之间的关系:完全不同的东西
下一步:测试线程是没有意义的。队列可以更改它使用的线程。这就是它们的用途
对你的问题:
如果在串行队列中向串行队列订阅块,则内部块必须等待外部块完成,因为它是串行队列。这是串行队列的性质。如果使用dispatch\u sync()执行此操作
调用方等待,直到块完成。因此,它永远不会完成:死锁。让我们来看看您的代码的简化版本:
dispatch_sync(self.serialQueue, // the caller waits for the code to be completed
^{
…
dispatch_sync(self.serialQueue, // the outer block waits for the code to be completed
^{
… // this code runs, after the outer block is completed.
});
…
});
内部块无法完成,因为它必须等待外部块完成(串行队列)。外部块无法完成,因为它等待内部块完成(同步)。死锁:两者都在等待另一个块完成
您想要完全不同的东西:您想要使用块的结果。只需将处理结果的代码传递到完成处理程序中。然后您可以使用完成处理程序中的结果立即返回:
- (void)someStringWithCompletionHandler:(void(^)(NSString *result))handler // No return type, but a completion handler
{
__block NSString *localSomeString;
dispatch_async(self.serialQueue,
^{
if ([NSThread isMainThread]) {
NSLog(@"main thread");
} else {
NSLog(@"background thread");
}
localSomeString = @"fuck you!";
handler( localSomeString );
});
}
然后这样称呼它:
- (void)goToNext
{
dispatch_async(self.serialQueue,
^{
[self someStringWithCompletionHandler:
^(NSSTring *result)
{
NSLog( @"%@", result );
}]);
});
}
输入Safari
顺便说一句:在代码中用注释标记点,而不是内联标记。否则,没有人可以复制和粘贴代码并让它运行。我从dispatch_sync文档“调用此函数并针对当前队列导致死锁”中知道第一个原因。但我不理解其余三种情况。