0

我有一个使用 NSThreads 执行并发任务的 iOS 应用程序。我将尝试将其迁移到使用 Grand Central Dispatch (GCD) 来处理并发。

问题是应用程序需要有关自给定时间以来创建了多少线程的信息。以及自给定时间以来产生的线程数当前正在运行。

目前,这是通过创建一个类别来完成的,该类别-mainNSThread. 在新的 swizzled 方法中,它只是增加正在运行的线程总数,然后在新的 swizzled-main方法返回之前减少相同的变量。

问题是当我使用 GCDdispatch_async时它不会创建一个NSThread,因此我的类别方法不起作用。在使用 GCD 处理并发时如何实现相同的目标?

我想检测的是何时将新块添加到 GCD,以及何时执行该块。

任何关于如何实现相同目标的建议都非常受欢迎。

编辑

非常感谢@ipmcc 和@RyanR 帮助我解决这个问题。:) 我相信我需要多讲一些关于背景和我想要完成的事情。

我实际上正在尝试的是扩展 iOS 测试框架FrankFrank在给定的应用程序中嵌入一个小型 Web 服务器,该服务器可以向 iOS 应用程序发送 HTTP 请求,从而模拟事件、滑动或点击手势作为示例。

我想以某种方式对其进行扩展,使其能够等到由特定模拟事件触发的所有工作都结束,然后再根据请求返回。

但是,我发现很难准确检测到接收到的事件触发了哪些工作。这就是我如何找到解决方案,只需重置一个线程计数器,然后在模拟事件后为所有创建的线程增加这个计数器,并在线程完成时减少它。然后阻塞直到线程数再次变为零。我知道这种方法也不完美,它不适用于 GCP。

还有其他方法可以实现吗?我想到的另一种可能的解决方案是指定除了处理 HTTP 请求的线程之外的所有内容都必须同步运行。但是我不知道这是否可能。

关于如何在每个模拟事件之后实现阻塞直到该事件触发的工作完成的任何建议?

4

2 回答 2

3

问题是应用程序需要有关自给定时间以来创建了多少线程的信息。以及自给定时间以来产生的线程数当前正在运行。

您将无法从 GCD 获得此信息。GCD 的要点之一是您不管理线程池。它是不透明的。您会注意到,即使是构建 NSThread 和 GCD 的底层线程库 pthreads 也没有(公共)方法来枚举所有现有线程或获取正在运行的线程数。如果没有硬核低级黑客,这将是不可行的。如果您需要控制或知道线程的数量,那么您需要成为生成和管理它们的人,而 GCD 对您来说是错误的抽象。

目前,这是通过创建一个类别来完成的,该类别在 NSThread 中的 -main 方法上执行一个方法。在新的 swizzled 方法中,它只是增加正在运行的线程总数,然后在新的 swizzled -main 方法返回之前减少相同的变量。

请注意,这只告诉您使用 NSThread 启动的线程数。如前所述,NSThread 是 pthread 之上的一个相当高级的抽象。没有什么可以阻止库代码使用 pthreads API 生成自己的线程,这些线程对您的计数是不可见的。

问题是当我使用 GCD dispatch_async 时它不会创建 NSThread,因此我的类别方法不起作用。在使用 GCD 处理并发时如何实现相同的目标?

简而言之,你不能。如果您想在各种框架中修补功能,那么您应该查找一个名为mach_override. (但请不要。)

我想检测的是何时将新块添加到 GCD,以及何时执行该块。

由于 GCD 使用线程池,因此添加块的行为并不意味着新线程。(这就是重点。)

如果您有一些有限的资源需要管理其消耗,那么传统的方法是使用限制信号量,但这只是一种选择。

这整个问题只是一个糟糕的设计。与 pthread 的数量一样,GCD 的队列宽度是不透明的/非公开的。您之前的解决方案不是特别可行(如所讨论的),进一步的努力可能会产生同样糟糕的解决方案。你真的应该重新考虑你的架构,这样知道有多少线程正在运行并不重要。

编辑:感谢您的澄清。从外部来看,并没有一种通用的方式来判断所有“工作”何时完成。如果一个操作设置了一个十分钟内不会回调的计时器怎么办?在极端情况下,请考虑以下情况:主运行循环在应用程序的整个生命周期中都在持续旋转,只要主运行循环在旋转,就可以在其上完成“工作”。

为了检测“完成”,您的应用程序必须发出完成信号。为了表示完成应用程序必须有某种方式(自身内部)来知道它已经完成。换句话说,应用程序不能告诉其他东西(即弗兰克)它不知道的东西。解决此问题的一种方法是将您在应用程序中所做的所有工作封装在 NSOperations 中。NSOperation/NSOperationQueue 提供了报告“完成”的好方法。在最简单的级别上,您可以将启动工作的代码包装在 NSBlockOperation 中,然后在该操作中添加一个完成块,在完成时发出其他信号,并将其排入 NSOperationQueue 以执行。(如果您更喜欢以 GCD 风格工作,dispatch_group您也可以这样做。)dispatch_group_notify

如果您对如何将应用程序的工作打包到 NSOperations 中存在具体问题,我建议您开始一个新问题。

于 2013-10-18T14:18:46.040 回答
2

您可以挂钩调度内省函数(introspection.h,方法都以 开头dispatch_introspection),但您必须链接到应该仅用于调试的库。我认为您不能将其包含在发布版本中。您最好的选择是将 GCD 封装到您自己的对象中,因此您的所有代码都提交块以通过该对象执行,并在跟踪您感兴趣的任何内容后将它们提交给 GCD。虽然您将无法跟踪线程消耗,因为 GCD 有意将其抽象化并重用线程。

于 2013-10-18T14:17:59.857 回答