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

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

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

以下是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的手册页说:

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

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

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

也就是说,似乎使用了记忆障碍。

在处理线程问题时,主要关心的是避免两个线程同时访问某些东西。 如果您正在使用串行队列,则不存在此问题。 通常哪个线程访问您的资源并不重要。 例如,我们使用串行队列来pipe理核心数据访问,而不会出现问题。

编辑:

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

  • 先决条件:
    • 一个NSMutableArray(我们称之为blockQueue )。
    • 一个NSCondition(我们称之为queueCondition )。
  • 创build一个新的NSThread。
    • 线程的方法有一个无限循环,在这个循环中,它locking条件,如果队列是空的,等待它(和“退出”布尔是假的),出队块并执行它。
  • locking条件的方法。

由于这种情况,线程只会在没有工作要做的情况下进入睡眠状态。

所以,大概(未经testing,假设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]; } 

在GCD中:不,对于当前的lib调度,这是不可能的。

块可以通过在任何可用的线程上调度lib来执行,而不pipe它们被分派到哪个队列。

主队列是一个例外,它总是在主线程上执行块。

请向苹果提交function请求,因为它看起来合理和合理。 但是我担心这是不可行的,否则就已经存在了;)

你可以使用NSOperationQueue 。 你可以使用方法- (void)setMaxConcurrentOperationCount:(NSInteger)count来使它只用一个线程。 将其设置为1

创build一个串行调度队列,并将所有调用调度到该串行调度队列。 所有的调用将在后台执行,但在同一个线程上依次执行。

如果你想在主线程中执行一个select器,你可以使用

 - (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait 

如果你想要它在后台线程执行

 - (void)performSelectorInBackground:(SEL)aSelector withObject:(id)object 

如果你想在其他任何线程执行GCD( Grand Central Dispatch

 double delayInSeconds = 2.0; dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)); dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ //code to be executed on the main queue after delay }); 

您可以使用MaxConcurrentOperationCount1 NSOperationQueue ,也可以使用NSOperationQueue模型(而不是Grand Central Dispatch)以手动方式进行。 使用后者,我build议你实现一个在线程中运行的worker-method,并从线程之外的队列或池中提取工作包(或命令)。 只要确保你使用locking/互斥/同步。

像这样,

 dispatch_asyn(dispatch_get_current_queue, ^ { }); 

从来没有尝试过,但这可能会伎俩。 对每个操作使用atomic分派队列的单独属性。

  @property (strong, atomic) dispatch_queue_t downloadQueue; 

排队/线程1为第一个操作

  downloadQueue = dispatch_queue_create("operation1", NULL); 

等等

由于atomic是线程安全的,因此downloadQueue不应该被其他线程访问。 所以它确保每个操作只有一个线程,其他线程不会访问它。