- mongodb - 在 MongoDB mapreduce 中,如何展平值对象?
- javascript - 对象传播与 Object.assign
- html - 输入类型 ="submit"Vs 按钮标签它们可以互换吗?
- sql - 使用 MongoDB 而不是 MS SQL Server 的优缺点
我遇到了一个场景,我有一个委托(delegate)回调,它可能发生在主线程或另一个线程上,直到运行时我才知道是哪个(使用 StoreKit.framework
)。
我还有需要在回调中更新的 UI 代码,这需要在函数执行之前发生,所以我最初的想法是有一个这样的函数:
-(void) someDelegateCallback:(id) sender
{
dispatch_sync(dispatch_get_main_queue(), ^{
// ui update code here
});
// code here that depends upon the UI getting updated
}
当它在后台线程上执行时,效果很好。但是,当在主线程上执行时,程序会陷入死锁。
这对我来说似乎很有趣,如果我正确阅读了 dispatch_sync
的文档,那么我希望它直接执行该 block ,而不用担心将其调度到运行循环中,如 here 所述:
As an optimization, this function invokes the block on the current thread when possible.
但是,这没什么大不了的,它只是意味着更多的打字,这导致我采用这种方法:
-(void) someDelegateCallBack:(id) sender
{
dispatch_block_t onMain = ^{
// update UI code here
};
if (dispatch_get_current_queue() == dispatch_get_main_queue())
onMain();
else
dispatch_sync(dispatch_get_main_queue(), onMain);
}
但是,这似乎有点倒退。这是 GCD 制作中的错误,还是我在文档中遗漏了什么?
最佳答案
dispatch_sync
做了两件事:
鉴于主线程是一个串行队列(这意味着它只使用一个线程),如果您在主队列上运行以下语句:
dispatch_sync(dispatch_get_main_queue(), ^(){/*...*/});
将发生以下事件:
dispatch_sync
将 block 放入主队列中。dispatch_sync
阻塞主队列的线程,直到该 block 完成执行。dispatch_sync
永远等待,因为应该运行 block 的线程被阻塞了。理解这个问题的关键是 dispatch_sync
不执行 block ,它只是将它们排队。将在运行循环的 future 迭代中执行。
以下做法:
if (queueA == dispatch_get_current_queue()){
block();
} else {
dispatch_sync(queueA, block);
}
非常好,但请注意,它不会保护您免受涉及队列层次结构的复杂场景的影响。在这种情况下,当前队列可能与您尝试发送 block 的先前阻塞队列不同。示例:
dispatch_sync(queueA, ^{
dispatch_sync(queueB, ^{
// dispatch_get_current_queue() is B, but A is blocked,
// so a dispatch_sync(A,b) will deadlock.
dispatch_sync(queueA, ^{
// some task
});
});
});
对于复杂的情况,在调度队列中读/写键值数据:
dispatch_queue_t workerQ = dispatch_queue_create("com.meh.sometask", NULL);
dispatch_queue_t funnelQ = dispatch_queue_create("com.meh.funnel", NULL);
dispatch_set_target_queue(workerQ,funnelQ);
static int kKey;
// saves string "funnel" in funnelQ
CFStringRef tag = CFSTR("funnel");
dispatch_queue_set_specific(funnelQ,
&kKey,
(void*)tag,
(dispatch_function_t)CFRelease);
dispatch_sync(workerQ, ^{
// is funnelQ in the hierarchy of workerQ?
CFStringRef tag = dispatch_get_specific(&kKey);
if (tag){
dispatch_sync(funnelQ, ^{
// some task
});
} else {
// some task
}
});
解释:
funnelQ
队列的 workerQ
队列。在实际代码中,如果您有多个“工作”队列并且您想要一次恢复/暂停所有队列(通过恢复/更新它们的目标 funnelQ
队列来实现),这将非常有用。funnelQ
。dispatch_sync
一些东西到 workerQ
,无论出于何种原因我想 dispatch_sync
到 funnelQ
,但避免将 dispatch_sync 发送到当前队列,因此我检查标签并采取相应措施。因为 get 沿着层次结构向上走,所以不会在 workerQ
中找到该值,但会在 funnelQ
中找到该值。这是一种找出层次结构中是否有任何队列是我们存储值的队列的方法。因此,为了防止 dispatch_sync 到当前队列。如果您想知道读取/写入上下文数据的函数,有以下三个:
dispatch_queue_set_specific
:写入队列。dispatch_queue_get_specific
:从队列中读取。dispatch_get_specific
:从当前队列中读取的便捷函数。键通过指针进行比较,并且从不取消引用。 setter 中的最后一个参数是释放键的析构函数。
如果您想知道“将一个队列指向另一个队列”,那就是这个意思。例如,我可以将队列 A 指向主队列,它会导致队列 A 中的所有 block 都在主队列中运行(通常是为了 UI 更新而这样做)。
关于objective-c - 为什么我们不能在当前队列上使用 dispatch_sync?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10984732/
请考虑以下代码: - (void)viewDidLoad { [super viewDidLoad]; dispatch_sync(dispatch_get_global_queue(
此代码阻塞了对 dispatch_sync 的调用。我是调度队列的新手。这会阻止什么原因? NSLog(@"%@",dispatch_get_current_queue()); NSLog(@"%@"
我有两个类,一个 View Controller 和另一个 (TwitterCrawler) 向 Twitter API 执行网络请求。我在加载 View Controller 时发出第一个网络请求,
以下代码中的死锁。为什么? dispatch_queue_t queue = dispatch_get_main_queue(); dispatch_async(queue, ^{ dispa
我正在研究 GCD 机制,我有几个问题。如果我的 Material 有误,请您纠正我,我将不胜感激。 1。问题) 据我所知,GCD 有 4 个具有不同优先级的全局并发队列。例如,当我们编写 DISPA
{ dispatch_queue_t myQueue = dispatch_queue_create("com.mycompany.myqueue", 0); dispatch_syn
是否可以杀死由于 dispatch_sync 而被锁定的线程?这是代码: dispatch_sync(q_, ^{ ... }); 这是锁定时的堆栈跟踪: #0 0x00007fff8d6995
我知道在串行队列上执行此操作会导致死锁,但我还没有发现任何提及在并发队列上执行此操作会导致死锁的内容。我只是想验证它不会死锁(它似乎不会,因为它只会阻塞队列中的一个线程,任务将在同一队列中的另一个线程
这个问题在这里已经有了答案: Why is this dispatch_sync() call freezing? (2 个答案) How to use background thread in s
我对读取共享资源时使用 dispatch_sync 有一些疑问。我在 Stack Overflow 上搜索了几个问题(例如:GCD dispatch_barrier or dispatch_sync?
我只是想确认为什么需要这样做。 我将此代码添加到 KIImagePager(一个 cocoapod)以加载应用本地的图像(默认代码从 url 加载图像)。 根据同事的建议,这是我的工作代码: disp
苹果文档说:(concurrencyProgrammingGuide,page49)重要提示:您永远不应从计划传递给函数的同一队列中执行的任务调用 dispatch_sync 或 dispatch_s
我知道这不是一个强有力的问题,但我必须弄清楚这个概念。 我定义了 myBlock 如下。 void(^myBlock)(void) = ^{ for(int i = 0;i < 10 ; i++
这是我需要做的。我希望 dispatch_sync 是使用 GCD 的最佳方式 我在 Appdelegate 的 applicationDidBecomeActive 回调中有一段临界区代码.. 我将
假设我从并发队列调用 dispatch_sync - 它会阻塞整个队列还是只阻塞那个执行线程? 最佳答案 dispatch_sync 会阻塞调用者线程直到执行完成,一个并发队列有多个线程所以它只会阻塞
我正在使用 dispatch_sync 执行一个 block ,并且该 block 已正确执行。但是这个 block 是在主线程上执行的。根据 Apple 文档: Serial queues (als
我遇到了一个场景,我有一个委托(delegate)回调,它可能发生在主线程或另一个线程上,直到运行时我才知道是哪个(使用 StoreKit.framework)。 我还有需要在回调中更新的 UI 代码
我最近在玩 UIDocument 并且混淆了 dispatch_sync/dispath_async 的概念 我有一个获取所有文档信息的方法 for (int i=0; i 所以 -openWithC
我有两个带有dispatch_sync的 block ,当第一个 block 结束时,我向用户显示窗口并开始运行第二个 block 。但在第二个 block 结束之前我不会单击屏幕上的任何按钮.. 看
我正在运行这段代码 dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ NSLog(@
我是一名优秀的程序员,十分优秀!