为什么我们不能在当前队列上使用dispatch_sync?

2024-06-10

我遇到了一个场景,我有一个委托回调,它可能发生在主线程或另一个线程上,并且直到运行时我才知道是哪个(使用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是的,那么我希望它直接执行该块,而不用担心将其调度到运行循环中,如上所述here https://developer.apple.com/library/mac/documentation/Performance/Reference/GCD_libdispatch_Ref/Reference/reference.html#//apple_ref/c/func/dispatch_sync:

作为一种优化,此函数会在可能的情况下调用当前线程上的块。

但是,这没什么大不了的,它只是意味着需要更多的打字,这导致我采用了这种方法:

-(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做了两件事:

  1. 将一个块排队
  2. 阻塞当前线程,直到该块完成运行

假设主线程是一个串行队列(这意味着它只使用一个线程),如果在主队列上运行以下语句:

dispatch_sync(dispatch_get_main_queue(), ^(){/*...*/});

将发生以下事件:

  1. dispatch_sync将块放入主队列中。
  2. dispatch_sync阻塞主队列的线程,直到该块执行完毕。
  3. dispatch_sync永远等待,因为该块应该运行的线程被阻塞。

理解这个问题的关键是dispatch_sync不执行块,它只是将它们排队。执行将在运行循环的未来迭代中发生。

采用以下方法:

if (queueA == dispatch_get_current_queue()){
    block();
} else {
    dispatch_sync(queueA, 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
    }
});

解释:

  • 我创建一个workerQ队列指向一个funnelQ队列。在实际代码中,如果您有多个“工作”队列并且您希望立即恢复/暂停所有队列(这是通过恢复/更新其目标来实现的),那么这非常有用funnelQ queue).
  • 我可以在任何时间点集中我的工作队列,因此要知道它们是否集中,我标记funnelQ用“漏斗”这个词。
  • 沿着路我dispatch_sync某事workerQ,无论出于什么原因我想要dispatch_sync to funnelQ,但避免将dispatch_sync发送到当前队列,因此我检查标签并采取相应措施。因为 get 会沿着层次结构向上走,所以不会在中找到该值workerQ但它会被发现在funnelQ。这是一种查明层次结构中是否有任何队列是我们存储值的队列的方法。因此,要防止对当前队列进行dispatch_sync。

如果您想知道读/写上下文数据的函数,有以下三个:

  • dispatch_queue_set_specific:写入队列。
  • dispatch_queue_get_specific:从队列中读取。
  • dispatch_get_specific:从当前队列读取的便捷功能。

键通过指针进行比较,并且永远不会取消引用。 setter 中的最后一个参数是释放键的析构函数。

如果您想知道“将一个队列指向另一个队列”,这正是这个意思。例如,我可以将队列A指向主队列,这将导致队列A中的所有块都在主队列中运行(通常这是为了UI更新而完成的)。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么我们不能在当前队列上使用dispatch_sync? 的相关文章

  • java 线程看不到共享布尔值更改

    这是代码 class Aux implements Runnable private Boolean isOn false private String statusMessage private final Object lock pub
  • iOS:两个 UIAlert 具有两种不同的委托方法

    我有一个 UIAlert UIAlertView alertView UIAlertView alloc initWithTitle ok message Canc delegate self cancelButtonTitle OK ot
  • 广播接收器和处理程序哪个更有效?

    我知道广播接收器的onReceive 和Handler的handleMessage 运行在同一个UI线程上 假设我想在同一个应用程序 进程 内的两个服务之间进行通信 我可以扩展广播接收器类并注册事件 OR 一个 Handler 然后将其实例
  • iOS 应用程序和.NET 应用程序之间的通信?

    我有 2 个应用程序 一个是 iOS 应用程序 一个是 NET 应用程序 我希望我的 iOS 应用程序发送一条消息 调用 NET 应用程序的方法 将一些字符串发送到 NET 应用程序以保存到数据库 那么 我的 iOS 应用程序如何与 NET
  • UIWebView didFinishLoading 多次触发

    我有一些代码需要在 a 之后运行UIWebView完成加载文档 为此我设置了UIWebView的委托给我的控制器 并实现了webViewDidFinishLoading method 这会被多次调用 具体取决于要加载的页面类型 我不确定是否
  • GKLocalPlayer 身份验证不起作用,但 isAuthenticated 返回 YES(游戏中心沙盒)

    我正在努力将回合制比赛集成到我的游戏中 几天前 我开始从 GameKit API 收到奇怪的错误 指出本地玩家未经过身份验证 尽管他已通过身份验证 当我启动应用程序时 authenticateHandler被调用 显示视图控制器 输入密码后
  • 从 iPhone 上的 NSString 中删除 HTML 标签

    有几种不同的方法可以删除HTML tags从一个NSString in Cocoa One way http cocoa karelia com Foundation Categories NSString Flatten a string
  • 外围 BLE 设备的唯一标识符

    所以我有外围设备BLE设备 我需要一些标识符以便稍后与另一部 iPhone 共享 我连接的示例iPhone A 为外围设备 iPhone A 将外围设备的标识符保存到数据库中 稍后我可以轻松获取iPhone B 并连接到通过该标识符找到的外
  • SplitViewController 与 TabbarController

    我在我的应用程序中使用分割视图功能 我必须将选项卡栏放在 rootViewController 中 但是 当我在选项卡栏中添加控制器并将它们添加到分割视图中时 它不会分割 它只显示detailViewController 这是应用程序中完成
  • 应用程序需要很长时间才能同步线程(或根本不同步)

    我在 Delphi XE5 iOS 和 Android 中使用 REST 组件 我目前正在通过 iOS 模拟器进行测试 我的应用程序often挂在我的代码中的以下行 R Request Execute 经过一些调试后 我发现它特别挂在 RE
  • 解析后 UITableView 委托和数据源在单独的类中

    我需要从一个单独的类设置 UITableView 委托和数据源 方法调用解析后数据准备就绪 但每次我的表都是空的 我正在使用 ARC 这是简化的代码 HomeViewController h import
  • 从 xib 中提取 UI 项目?

    经过一番浏览文档后 我决定使用以下技术 使用 viewWithTag 从 loadNibNamed owner options 返回的主根视图中提取子视图 首先 我有点困惑 因为我假设 loadNibNamed owner options
  • 核心数据:解决一个奇怪的 EXC_BAD_ACCESS 错误

    我在核心数据方面面临着一个非常奇怪的问题 我们来描述一下 定义 假设我有两个模型 ModelA and ModelB 在数据模型中ModelA有参考ModelB作为一对多关联 因此ModelB与 具有一对一关联ModelA Update 当
  • 快速找到一个数字的下一个倍数的方法

    我需要找到从基数开始的数字的第一个倍数 例如 7 中 3 的第一个倍数是 9 我的第一次尝试是这样做 multiple baseNumber while multiple number 0 multiple 最后 multiple 将具有第
  • UIAlertView 中的 MPVolumeView?

    是否可以将 MPVolumeView 放入 UIAlertView 中 我已经尝试过put它在里面 但不显示 这可能是sizeToFit or initWithFrame 部分 有没有办法测试是否MPVolumeView实际上正在被创建吗
  • 如何使用MemoryCache代替Timer来触发一个方法?

    以下方法通过等待已运行操作的结果来处理并发请求 对数据的请求可能会使用相同 不同的凭据同时出现 对于每组唯一的凭据 最多可以有一个GetCurrentInternal呼叫正在进行中 当准备就绪时 该呼叫的结果将返回给所有排队的服务员 pri
  • 无限 UIScrollView 在 iOS4.3 中出现奇怪的行为,而不是 iOS5

    我已经实现了一个包含 UIView 的无限 UIScrollView 在 iOS5 模拟器和 iPhone 中滚动时 效果非常好 但在 iOS 4 3 sim 和手机 中 情况有点疯狂 滚动条传递的视图比应有的多 大约比 iOS5 多 10
  • 如何将 #ifdef DEBUG 添加到 Xcode?

    我的项目中有一些代码永远不应该在发布版本中使用 但在测试时很有用 我想做这样的事情 ifdef DEBUG Run my debugging only code endif 在 Xcode 4 中哪里添加 DEBUG 设置 我尝试将其放入
  • iOS:addConstraints:应用程序崩溃

    Problem 我似乎无法在现有项目中采用自动布局 Details 我之前也遇到过与此问题相同的问题presentViewController 在 iOS 但所提供的答案都不是我的解决方案 我正在使用所有没有 xib 的故事板视图 我的 使
  • Objective-C 声明的 @property 属性(非原子、复制、强、弱)

    有人可以向我详细解释一下我何时必须使用每个属性 nonatomic copy strong weak等等 对于声明的属性 并解释每个属性的作用是什么 某种例子也很好 我正在使用ARC 非原子的 Nonatomic https stackov

随机推荐

  • 当使用带 _id 的复合分片键时,MongoDB 是否确保唯一的 _id 字段值

    我想启动分片 如您所知 分片键非常重要 我发现 使用 id 以外的分片键时 MongoDB 不确保 id 字段值唯一 http docs mongodb org manual faq sharding how does mongodb en
  • Pechkin HTML 到 PDF,其中包含指向无扩展名 PNG 的链接

    我正在尝试使用 Pechkin Synchronized WkHtmlToPDF 将 HTML 字符串转换为 PDF 除了一个 破坏交易的 部分之外 一切都很完美 作为 HTML 字符串的一部分 我有一个 Image 标签 它引用通过 SS
  • 如何暂时禁用地图标记聚类?

    我正在使用适用于 Android 的 Google Maps V2 以及maps utils 扩展库来进行标记聚类 应用程序的某些部分不需要获取聚集标记 有没有什么方法可以禁止 clusterManager 对标记进行聚类 并在某些条件后让
  • 如何在 React 中使用单选按钮?

    我正在制作表格 并且需要无线电输入 如何在 onSubmit 函数中获取已检查的无线电输入 正确的方法是什么 这是我的代码 当我提交时 我的 myRadioInput variable 包含选项 A 或选项 B React createCl
  • 如何分析 Stockfish 中的位置得分

    我有一个FEN https en wikipedia org wiki Forsyth E2 80 93Edwards Notation我想分析一下哪个位置更强 例如我有这个职位 rnbq1bnr pp2k2N 8 2p1p2Q 4N3 8
  • TinyMCE 显示为 A4

    我的网站上有一个 TinyMCE 编辑器 我希望以 A4 格式显示可编辑区域 或整个内容 基本上 我想以与在 MS Word 中相同的方式查看文档 宽度 分页符等 这可能吗 请为我指明正确的方向 每个人都说这很难 但谷歌已经在 Google
  • Python脚本不打印输出[重复]

    这个问题在这里已经有答案了 我有这个简单的Python程序 def GetNum Text x input Input something while x gt 0 x input Input something print x 我想通过终
  • 错误:1449,“指定为定义者的用户 ('root'@'localhost') 不存在”

    当我尝试通过应用程序检索数据或将数据插入数据库时 出现上述错误 过程代码如下 CREATE DEFINER root localhost PROCEDURE sp createUser IN p name VARCHAR 20 IN p u
  • 如何让“允许访问文件 URL”复选框显示在我的应用程序旁边?我在清单中有文件写入权限

    更多信息 更新 我打包并安装了谷歌自己的示例应用程序 显示文件系统访问权限 它也确实如此not显示复选框 你可以在这里找到它 https github com GoogleChrome chrome app samples tree mas
  • 使用signalR将聊天对话存储在sql数据库中

    我正在开发一个类库 其中包含适用于这些场景的通用方法 实时支持聊天 一对一私人文本聊天 与许多管理员和访客 拥有许多用户的房间 您可以在其中发送广播和私人消息 上面这两个功能已经实现 现在我的应用程序需要保存消息 我的问题是 在 SQL 数
  • GWT 编译器忽略方法的注释

    是否可以创建注释 或其他方式 来强制 GWT 编译器不编译方法 我有一个类 我也在应用程序引擎上使用 在共享文件夹中 其中的一个方法需要一个仅服务器端的函数 这会导致 GWT 无法编译 我希望 GWT 忽略该方法 而 appengine 则
  • 无法加载 DLL(找不到模块 HRESULT:0x8007007E)

    我有一个 dll 库 其中包含我需要在 NET 4 0 应用程序中使用的非托管 C API 代码 但我尝试加载 dll 的每种方法都会出现错误 无法加载 DLL MyOwn dll 找不到指定的模块 HRESULT 异常 0x8007007
  • JBoss 7 中带有 HornetQ 的 JMS 队列的“持久”属性是什么意思?

    在使用 HornetQ 基于standalone full xml 配置 的 JBoss 7 上配置 JMS 队列期间 我注意到一个属性 持久 我浏览了几个来源 其中许多都表示队列始终是 持久的 这意味着消息将始终被传递 即使潜在的接收者在
  • Spring MVC 中的重定向

    为什么我不能让它在我的控制器中工作 RequestMapping method RequestMethod POST public String onSubmit Model model ModelAttribute form Form f
  • 如何在 WPF textBlock 控件中滚动文本?

    HI 我是 WPF 新手 正在寻找在 WPF 应用程序中滚动文本的解决方案 我尝试了一些动画 但遇到了剪辑问题我在以下地方找到了解决我的问题的可能方法 http social msdn microsoft com forums en US
  • redis能完全取代mysql吗?

    简单的问题 我是否可以使用 redis 而不是 mysql 来处理各种 Web 应用程序 社交网络 地理位置服务等 IT 领域没有什么是不可能的 但有些事情可能会变得极其复杂 将键值存储用于全文搜索之类的事情可能会非常痛苦 另外 据我所知
  • 在 ES6 中使用 import 和 require 的正确方法是什么?

    关于 import 和 require 及其差异有多个问题 像这些 JavaScript 中的 import 和 require 有什么区别 https stackoverflow com questions 51373933 what i
  • 获取正确的 JSON 格式

    所以我试图创建一个 JSON 对象 它应该为我保存一些有关某些问题的信息 这是我希望如何呈现它的伪代码 page 1 info id 1 type 3 description How to do JSON alternatives id 1
  • Keycloak 使用不同的客户端重新验证经过身份验证的用户

    如果我有一个用户已通过 keycloak 与领域 R 下的公共客户端 C1 进行身份验证 那么我可以在 keycloak 中点击一个端点 该端点将为同一领域 R 下的不同公共客户端 C2 生成新的访问令牌吗 更新 1 我尝试使用刷新令牌为
  • 为什么我们不能在当前队列上使用dispatch_sync?

    我遇到了一个场景 我有一个委托回调 它可能发生在主线程或另一个线程上 并且直到运行时我才知道是哪个 使用StoreKit framework 我还需要在该回调中更新 UI 代码 该回调需要在函数执行之前发生 所以我最初的想法是拥有一个如下所