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 中如何将代码块分派到同一个线程? 的相关文章

随机推荐

  • 如何管理访问 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 在同一个线程上运行 我想在后台运行一些耗时的操作 但这些操作必须在同一线程上运行 因为它们涉及资源 而不能在线程之间共享 如果需要 更多技