gpt4 book ai didi

ios - 如何将代码块分派(dispatch)到 iOS 中的同一个线程?

转载 作者:IT王子 更新时间:2023-10-29 06:18:27 24 4
gpt4 key购买 nike

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

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

这是 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];
}];
}

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

最佳答案

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

dispatch_queue_create 的手册页说:

Queues are not bound to any specific thread of execution and blocks submitted to independent queues may execute concurrently.

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

All memory writes performed by a block dispatched to a serial queue are guaranteed to be visible to subsequent blocks dispatched to the same queue.

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

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

编辑:

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

  • 先决条件:
    • 一个 NSMutableArray(我们称它为 blockQueue)。
    • 一个 NSCondition(我们称之为 queueCondition)。
  • 创建一个新的 NSThread。
    • 线程的方法有一个无限循环,在这个循环中它锁定条件,如果队列为空(并且“退出” bool 值是假的)等待它,出队一个 block 并执行它。
  • 锁定条件并使 block 排队的方法。

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

所以,大致(未经测试,假设 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()
}

关于ios - 如何将代码块分派(dispatch)到 iOS 中的同一个线程?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22091696/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com