iOS 中如何将代码块分派到同一个线程?

2024-04-03

问题的主要方面:这是关于 iOS 的。我能否以某种方式分派代码块,使它们全部(a)在后台运行并且(b)在同一个线程上运行?我想在后台运行一些耗时的操作,但这些操作必须在同一线程上运行,因为它们涉及资源,而不能在线程之间共享。

如果需要,更多技术细节:它是关于为 Apache Cordova 实现 sqlite 插件,Apache Cordova 是移动平台上的 HTML5 应用程序框架。这个插件应该是一个实现WebSQL http://www.w3.org/TR/webdatabase/通过 Cordova 的插件 API 的方式。 (这意味着,不可能将整个交易包装在单个块中,这可以使一切变得更容易。)

以下是 Cordova 文档中的一些代码:

- (void)myPluginMethod:(CDVInvokedUrlCommand*)command
{
    // Check command.arguments here.
    [self.commandDelegate runInBackground:^{
        NSString* payload = nil;
        // Some blocking logic...
        CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:payload];
        // The sendPluginResult method is thread-safe.
        [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
    }];
}

但据我所知,不能保证那些分派的代码块(参见runInBackground)将在同一线程上运行。


GCD 不保证两个块在同一个线程上运行,即使它们属于同一个队列(当然主队列除外)。然而,如果您使用串行队列(DISPATCH_QUEUE_SERIAL)这不是问题,因为您知道没有对数据的并发访问。

的手册页dispatch_queue_create says:

队列不绑定到任何特定的执行线程,提交到独立队列的块可以同时执行。

我不知道有什么方法可以将队列绑定到特定线程(毕竟,不需要关心线程是 GCD 的一个要点)。您可以使用串行队列而不用担心实际线程的原因是这样的:

调度到串行队列的块执行的所有内存写入都保证对调度到同一队列的后续块可见。

也就是说,似乎使用了内存屏障。

在处理线程问题时,您主要关心的通常是避免两个线程同时访问某些内容。如果您使用串行队列,则不会遇到此问题。通常并不重要which线程正在访问您的资源。例如,我们使用串行队列来毫无问题地管理核心数据访问。

Edit:

看来您确实发现了一种罕见的情况,您需要在同一线程上工作。您可以实现自己的工作线程:

  • Prerequisites:
    • 一个 NSMutableArray (我们称之为blockQueue).
    • 一个 NSCondition (我们称之为queueCondition).
  • Create a new NSThread.
    • 线程的方法有一个无限循环,其中锁定条件,如果队列为空(并且“quit”布尔为假)则等待它,使块出列并执行它。
  • 锁定条件并将块排入队列的方法。

由于这种情况,线程将在没有工作可做时简单地休眠。

所以,粗略地(未经测试,假设 ARC):

- (void)startWorkerThread
{
    workerThread = [[NSThread alloc]
        initWithTarget:self
        selector:@selector(threadMain)
        object:nil
    ];
    [workerThread start];
}

- (void)threadMain
{
    void (^block)();
    NSThread *currentThread;

    currentThread = [NSThread currentThread];

    while (1) {
        [queueCondition lock];
        {
            while ([blockQueue count] == 0 && ![currentThread isCancelled]) {
                [queueCondition wait];
            }

            if ([currentThread isCancelled]) {
                [queueCondition unlock];
                return;
            }

            block = [blockQueue objectAtIndex:0];
            [blockQueue removeObjectAtIndex:0];
        }
        [queueCondition unlock];

        // Execute block outside the condition, since it's also a lock!
        // We want to give other threads the possibility to enqueue
        // a new block while we're executing a block.
        block();
    }
}

- (void)enqueue:(void(^)())block
{
    [queueCondition lock];
    {
        // Copy the block! IIRC you'll get strange things or
        // even crashes if you don't.
        [blockQueue addObject:[block copy]];
        [queueCondition signal];
    }
    [queueCondition unlock];
}

- (void)stopThread
{
    [queueCondition lock];
    {
        [workerThread cancel];
        [queueCondition signal];
    }
    [queueCondition unlock];
}

未经测试的 Swift 5 端口:

var workerThread: Thread?
var blockQueue = [() -> Void]()
let queueCondition = NSCondition()

func startWorkerThread() {
    workerThread = Thread() {
        let currentThread = Thread.current
        while true {
            self.queueCondition.lock()
            while self.blockQueue.isEmpty && !currentThread.isCancelled {
                self.queueCondition.wait()
            }

            if currentThread.isCancelled {
                self.queueCondition.unlock()
                return
            }

            let block = self.blockQueue.remove(at: 0)
            self.queueCondition.unlock()

            // Execute block outside the condition, since it's also a lock!
            // We want to give other threads the possibility to enqueue
            // a new block while we're executing a block.
            block()
        }
    }
    workerThread?.start()
}

func enqueue(_ block: @escaping () -> Void) {
    queueCondition.lock()
    blockQueue.append(block)
    queueCondition.signal()
    queueCondition.unlock()
}

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

iOS 中如何将代码块分派到同一个线程? 的相关文章

  • iPad 何时清除库/缓存?

    为了响应 Apple 对 iOS 数据存储指南的更改 我最近重新配置了一个 iPad 应用程序 将其文档 50MB 存储在库 缓存文件夹中 在 iOS 模拟器中进行测试期间 当我模拟更新时 遵循 Brad Larsson 的建议 https
  • 如何在 UITableView 的附件视图中添加多个按钮?

    我想在 UITableView 的附件视图中添加两个相邻的自定义按钮 我尝试做cell accessoryView customButton 进而cell accessoryView customButton2 很明显 这个按钮取代了之前的
  • 使用accesskey和secretkey从S3服务器下载安全文件

    我正在尝试使用 NSURLSessionDownloadTask 从 S3 服务器下载安全文件 但它返回 403 错误 访问被拒绝 My Code NSMutableURLRequest request NSMutableURLReques
  • 如何使用 Swift 循环 Array> [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 给我一个 循环遍历 的例子和解释array
  • 将数据从子模态 VC 传递到父视图控制器的最佳方法?

    将数据从子模式视图传递到父视图控制器的最佳方法是什么 我的 iPad 应用程序上有一个子模式登录屏幕 我想将用户信息传回父级分割视图控制器 我正在考虑使用 NSNotification 但我不确定这是否是将数据传递回父级的最简单 最有效的方
  • ios7.1:推送通知徽章更新问题

    我已经设置了Push Notification在我当前的项目之一中 我已遵循推送通知所需的所有说明 在 tag ios7 中工作正常 但在7 1当我的应用程序处于后台模式时 我在徽章更新中遇到问题 我的代码如下 BOOL applicati
  • RestKit:如何删除核心数据条目以保持内容与服务器同步?

    我正在使用 RestKit RKObjectManager 从我的服务器获取数据并将其存储在核心数据中 请参阅我的其他post https stackoverflow com questions 17066214 restkit how t
  • iOS:GMail API - 通过电子邮件发送附件

    我能够成功发送没有附件的电子邮件 但是 当我尝试使用 GTLUploadParamaters 上传附件时 出现 501 错误 我尝试添加照片库中附件的 NSData 以及仅发送图像的 URL 在这两种情况下我都得到了同样的错误 Create
  • 自动布局+基于总行数的动态表高度约束

    首先 这与动态单元格的高度无关 所以不要把它搞混了 我有一个场景 我创建了三张卡 详细信息卡 显示位置的具体详细信息 图表卡 根据选择显示不同的图表 更多详细信息卡 卡显示更多详细信息 以下是上述卡片的屏幕 查看以上屏幕的层次结构 Cont
  • 有没有办法以编程方式选择 Segue 锚点?

    假设我有一个 Storyboard 其中包含一个包含按钮的视图 当用户按下此按钮时 会出现一个弹出窗口 因此 我需要使用 Xcode 将 Segue 拖动到按钮来设置锚点 然后执行使用标识符执行Segue 所以 我的问题是 有没有办法以编程
  • iOS 上的三字母国家代码

    我知道您可以在 iOS 上获取所有国家 地区的两个字母的国家 地区代码 但是有没有办法获得三个字母的国家代码 So from http en wikipedia org wiki ISO 3166 1 alpha 2 http en wik
  • 如何更改某些功能以兼容 iOS 10 或更低版本的 Snapchat 中的某些功能,例如相机视图控制器

    我正在制作一个视图控制器来制作像 snapchat 相机一样的相机视图控制器 我下面的代码在 iOS 11 或更高版本上完美运行 老实说 我并没有真正掌握我的代码 因为我只是按照这个像相机视图控制器这样的 snapchat 的教程进行操作
  • 从钥匙串保存和加载 |斯威夫特[重复]

    这个问题在这里已经有答案了 如何简单地将字符串存储在钥匙串中并在需要时加载 有几种SO解决方案 主要参考Git repo 但我需要最新 Swift 上最小和最简单的解决方案 当然 我不想添加 git 框架来简单地在我的项目中存储密码 有类似
  • iOS TestFlight - 外部测试人员未收到新版本通知

    我已经向外部 TestFlight 用户提供了一个应用程序 他们已收到电子邮件并按预期安装了应用程序 他们有版本 1 0 Build 1 不过 我现在已经上传了一个新版本 版本 1 0 版本 2 这已获得批准 在外部测试页面中 我添加并选择
  • iOS 9.3 出现新的 UIPDFPageRenderOperation 错误?

    我正在向 UIWebView 添加一些 PDF 链接 每次加载并做出滚动手势时 都会收到此错误 objc 910 UIPDFPageRenderOperation 对象 0x14acaca10 过度释放 当已经解除分配时 打断 objc o
  • Xcode 和 Waze 集成

    我正在尝试整合我的app with waze http www waze com 有人知道如何调用位智并发送坐标吗 我没有找到任何 API 或其他相关信息 void navigateToLatitude double latitude lo
  • NSLocale 货币符号,显示金额值之前或之后

    我在用StoreKit在我的应用程序中实现应用程序内购买商店 我有一个自定义设计 这意味着价格的值应该是白色的且较大的 货币符号较小 较暗并与价格值的顶部对齐 我可以使用以下命令毫无问题地获取货币符号NSLocale in SKproduc
  • 启动时运行后台任务

    我正在编写一个 iOS 应用程序 它使用 Dropbox Datastore API 在多个设备之间同步数据 在 Android 上 我可以告诉服务在启动时启动 这使其能够同步 设备关闭时可能发生的任何更改 我无法找到让我的应用程序在 iO
  • Base64Transcoder.m 重复符号

    我想使用 SKPSMTPMessage 库 唯一的问题是这个库包含文件 Base64Transcoder m 由于我有 Dropbox SDK 该文件会出现重复错误 我该如何解决这个错误 我不能直接删除 Base64Transcoder m
  • 如何使用 UISlider 以及如何将滑块设置为特定值?

    我是第一次使用 UIslider 首先我想知道如果值的范围是 0 到 10 如何获取滑块位置的值 其次 我希望我的滑块设置为 5 个不同的值 如 1 2 3 4 5 slider should not set between the lab

随机推荐

  • 如何管理访问 Django REST API 的权限?

    我正在构建一个公开 REST API 的 Django 应用程序 用户可以通过该 API 查询我的应用程序的模型 我正在按照说明进行操作here http www django rest framework org tutorial qui
  • UJS、AJAX、Rails 4、form_for collection_select 将值传递到方法并将值返回到表单

    我对 Rails 非常陌生 因此在一起处理 AJAX UJS 和 Rails 时遇到很多困惑 我查看了railscast 几个SO答案 尝试了freenode上的 rubyonrails IRC频道 唉 我还是被困住了 无论如何 这是我的问
  • MVC 和 WebForms 之间共享大师 - 处理

    我们有一个大型遗留应用程序 我们希望开始使用 MVC 来实现新功能 为此 我们添加了自定义路由 例如 routes IgnoreRoute allaspx new allaspx as pmh x 我们希望在旧的 WebForms 和新的
  • 闪烁动画WPF

    我有这个动画 一种闪烁动画 这样当单击按钮时 矩形就会 闪烁 我已经写了一个动画代码 只是想知道是否有更好的方法来实现这个动画 有什么建议么 代码如下
  • Math.Tan() 接近 -Pi/2 在 .NET 中错误,在 Java 中正确?

    我的单元测试失败了Math Tan PI 2 在 NET 中返回错误版本 预期 值取自 Wolfram 在线 使用 Pi 2 的拼写常数 自己看看here http www wolframalpha com input i tan 28 1
  • 如何在 IntelliJ 中移动工具栏?

    如何将 IntelliJ 中的工具栏从右上角移动到左上角 单击主菜单 查看 工具栏
  • JQuery 设置本地存储变量

    我在获取本地存储变量来存储正确的值时遇到一些问题 它的要点是我想显示局部变量的内容 然后如果用户单击 它会从 xml 文件中提取数据 并将其保存到局部变量中 问题是 它没有正确保存到局部变量 我尝试了多种语法来让它工作 但我没有想法 它的测
  • 有元数据驱动的 UI 示例代码吗?

    我正在设计一个使用元数据驱动 UI 的 net windows 窗体应用程序 除了寻找http msdn microsoft com en us library ms954610 aspx http msdn microsoft com e
  • 通过 javascript 录制网站的内部音频

    i made 这个网络应用程序 https sky music herokuapp com songComposer html为了创作音乐 我想添加一个功能来将作品下载为 mp3 wav whateverFileFormatPossible
  • java.lang.OutOfMemory错误:

    我正在尝试根据从数据库检索的字节创建视频文件 该程序在几个小时前就运行良好 上传大文件后 当我尝试检索它时 它会产生错误java lang OutOfMemoryError 我的代码是 conn prepareConnection Stri
  • SVG、文本、固定宽度/高度的字体

    我试图让 SVG 文本 元素适合 svg 矩形 元素 例如在下面的示例中 我使用了 5 个字符的等宽文本 字体大小为 100px 并且我希望有一个靠近文本的边框 但文本右侧有一个空白
  • Spring AMQP - 使用带 TTL 的死信机制进行消息重新排队

    就像是 休斯顿 我们这里有问题 在第一次尝试处理事件失败后 我需要安排 延迟消息 5 分钟 我在这种情况下实现了死信交换 失败时的消息将路由至 DLX gt 重试队列 并在 TTL 为 5 分钟后返回工作队列以进行另一次尝试 这是我正在使用
  • 安装程序启动时间长 - 在 wpWelcome 之前添加对话框?

    我使用 Inno Setup 创建的安装程序大小约为 850 MB 包含约 7000 个文件和 890 个文件夹 未压缩大小为 1 98 GB 当开始安装过程时 之后Windows UAC 对话框出现后 安装程序的图标为空Taskbar约
  • 如何在Python OpenCV中删除轮廓内部的轮廓?

    Python中的OpenCV提供了以下代码 regions hierarchy cv2 findContours binary image cv2 RETR LIST cv2 CHAIN APPROX SIMPLE for region i
  • Android:无法找到或加载主类org.gradle.wrapper.GradleWrapperMain

    我正在尝试在 GitLab CI 上构建我的项目 但不幸的是 我在运行器中不断收到此错误 Error Could not find or load main class org gradle wrapper GradleWrapperMai
  • 如何删除/卸载嵌套的反应组件

    我想卸载单个反应组件 该组件属于总共包含三个组件的父组件 父组件有这个渲染函数 render function return div div
  • 使用 scrapy 抓取多个页面

    我正在尝试使用 scrapy 抓取多个网页 页面的链接如下 http www example com id some number 在下一页中 末尾的数字减少了1 所以我正在尝试构建一个蜘蛛 它可以导航到其他页面并抓取它们 我的代码如下 i
  • Rails 字体 CORS 政策

    我无法为 CORS 策略加载此字体 Folder app assets fonts Inter UI var woff2 Error 访问字体位于 http localhost 3000 assets Inter UI var e2e323
  • android中处理html webview的onclick功能

    我正在尝试处理 android referred 中 html 的 onclick在此输入链接描述 https stackoverflow com questions 4065312 detect click on html button
  • iOS 中如何将代码块分派到同一个线程?

    问题的主要方面 这是关于 iOS 的 我能否以某种方式分派代码块 使它们全部 a 在后台运行并且 b 在同一个线程上运行 我想在后台运行一些耗时的操作 但这些操作必须在同一线程上运行 因为它们涉及资源 而不能在线程之间共享 如果需要 更多技