需要关于调度队列,线程和NSRunLoop的一些说明

以下是我所知道和了解的内容:

全局队列是一个可以将任务分派给多个线程的并发队列。 执行任务的顺序不能保证。 例如:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), { for (int i; i<10; i++) { doTask() } }) 

如果我想调度到串行队列,我可以使用

 dispatch_async(dispatch_queue_create("my.serial.queue", nil) { ... } 

每次只有一个任务被调度到一个线程并被执行。 订单是先进先出。

=====我感到困惑和不完全理解=======

  1. 主线程有一个NSRunLoop,在主线程中循环任务。 我想知道调度队列和运行循环之间的关系是什么? 我可以理解,如果调度一个任务到主线程,主线程的NSRunLoop得到调度任务并执行它?

  2. 把任务分派给多个线程的全局队列呢? iOS / OSX系统不仅自动创build线程,还为每个线程创buildNSRunLoop? 然后每个线程的运行循环从全局队列中获取调度的任务并执行它?

  3. 谁知道线程? dispatch_async()dispatch_sync()函数知道哪个线程调度任务,或者队列知道哪个线程调度任务?

  4. 有没有办法从程序调度队列中获取线程的NSRunLoop对象(调度任务)? (这个问题与问题3有关)

  1. 主线程的运行循环有一个步骤,它运行在主队列上排队的任何块。 如果你想了解运行循环做了什么,你可能会发现这个答案很有用。

  2. GCD为并发队列创build线程。 一个线程没有运行循环,直到第一次在线程上运行的东西要求线程的运行循环,此时系统为该线程创build一个运行循环。 然而,运行循环只有在该线程上的某些东西要求它运行时才会运行(通过调用-[NSRunLoop run]CFRunLoopRun或类似的方法)。 大多数线程(包括为GCD队列创build的线程)从不具有运行循环。

  3. GCDpipe理一个线程池,当它需要运行一个块(因为它被添加到某个队列)时,GCDselect运行该块的线程。 GCD的线程selectalgorithm大多是一个实现细节,只不过它会一直为添加到主队列的块select主线程。 (请注意,GCD有时也会将主线程用于添加到其他队列的块。)

  4. 你只能得到主线程的运行循环(使用+[NSRunLoop mainRunLoop]CFRunLoopGetMain )或当前线程的运行循环(使用+[NSRunLoop currentRunLoop]CFRunLoopGetCurrent )。 如果您需要某个任意线程的运行循环,则必须find一种方法来在该线程上调用CFRunLoopGetCurrent ,并以安全,同步的方式将其返回值传递回线程。

    请注意, NSRunLoop接口不是线程安全的,但CFRunLoop接口线程安全的,所以如果您需要访问另一个线程的运行循环,则应该使用CFRunLoop接口。

    另外请注意,你可能不应该在GCD队列中运行一个块的时间内运行一个很长的运行循环,因为你正在绑定一个GCD希望控制的线程。 如果您需要长时间运行一个运行循环,则应该为其启动自己的线程。 你可以在CFStream.c的_legacyStreamRunLoop函数中看到这个例子。 请注意,它是如何使专用线程的运行循环在名为sLegacyRL的静态variables中sLegacyRL ,它在dispatch_semaphore_t的保护下初始化。

  1. 主线程的运行循环与主调度队列之间的关系仅仅是它们都在主线程上运行,并且调度到主队列的块在主线程上交错,而在主运行循环上处理事件。

    正如“ 并发编程指南”所说:

    主调度队列是全局可用的串行队列,用于执行应用程序主线程上的任务。 该队列与应用程序的运行循环(如果存在的话)一起工作,以便将执行排队的任务与执行附加到运行循环的其他事件源进行交错。 由于它在应用程序的主线程上运行,因此主队列通常用作应用程序的关键同步点。

  2. 当调度到后台线程时,它不会为这些工作线程创build一个NSRunLoop 。 你通常也不需要这些后台线程的运行循环。 我们过去必须为后台线程创build我们自己的NSRunLoop (例如,当在后台线程上调度NSURLConnection时),但是这种模式不再经常需要。

    对于历史上需要运行循环的事情,如果在后台线程上运行,通常会有更好的机制。 例如,而不是NSURLConnection ,你现在使用NSURLSession 。 或者,而不是后台线程上的NSRunLoop NSTimer ,你会创build一个GCD定时器调度源。

  3. 关于谁“知道”线程,工作线程在分派到队列时被识别。 线程不是队列的属性,而是在队列需要时分配给队列。

  4. 如果你想为一个工作者线程创build一个NSRunLoop (无论如何你通常不应该这样做),你可以创build它并自己跟踪它。 而且,当用一个运行循环来调度一个线程时,我会倾向于自己创buildNSThread并安排运行循环,而不是捆绑GCD的一个工作线程。