2017-07-02 31 views

回答

1

大中央调度(GCD)提供了一个“主队列”(使用DispatchQueue.main斯威夫特访问)。主队列总是在主线程上运行其块。

由于Apple平台上的应用程序通常在主线程上运行RunLoop.main,因此运行循环与GCD协同运行添加到主队列中的块。

因此,当创建主线程的运行循环时,它会创建一些GCD对象,并使GCD自行初始化。部分GCD初始化涉及创建一个“工作队列”和一个线程池,用于运行添加到工作队列的作业。

您可以看到创建线程的是运行循环的创建,而不是运行循环。这里有一个示例程序:

#import <Foundation/Foundation.h> 

int main(int argc, const char * argv[]) { 
    [NSRunLoop currentRunLoop]; // line 4 
    return 0;     // line 5 
} 

在终端中,我运行lldb(调试器)。我告诉它调试test程序,在第4行设置一个断点,然后运行。当它在断点处停止(调用currentRunLoop之前,我列出的所有主题:

:; lldb 
"crashlog" and "save_crashlog" command installed, use the "--help" option for detailed help 
(lldb) target create test 
Current executable set to 'test' (x86_64). 
(lldb) b 4 
Breakpoint 1: where = test`main + 22 at main.m:4, address = 0x0000000100000f46 
(lldb) r 
Process 12087 launched: '/Users/mayoff/Library/Developer/Xcode/DerivedData/test-aegotyskrtnbeabaungzpkkbjvdz/Build/Products/Debug/test' (x86_64) 
Process 12087 stopped 
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1 
    frame #0: sp=0x00007fff5fbff240 fp=0x00007fff5fbff260 pc=0x0000000100000f46 test`main(argc=1, argv=0x00007fff5fbff280) + 22 at main.m:4 
    1  #import <Foundation/Foundation.h> 
    2  
    3  int main(int argc, const char * argv[]) { 
-> 4   [NSRunLoop currentRunLoop]; // line 4 
    5   return 0; // line 5 
    6  } 
Target 0: (test) stopped. 
(lldb) thread list 
Process 12087 stopped 
* thread #1: tid = 0x1066d3, 0x0000000100000f46 test`main(argc=1, argv=0x00007fff5fbff280) at main.m:4, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1 

只有一个线程接下来,我跨过调用currentRunLoop,再次列出的所有主题。

(lldb) n 
Process 12087 stopped 
* thread #1, queue = 'com.apple.main-thread', stop reason = step over 
    frame #0: sp=0x00007fff5fbff240 fp=0x00007fff5fbff260 pc=0x0000000100000f69 test`main(argc=1, argv=0x00007fff5fbff280) + 57 at main.m:5 
    2  
    3  int main(int argc, const char * argv[]) { 
    4   [NSRunLoop currentRunLoop]; // line 4 
-> 5   return 0; // line 5 
    6  } 
Target 0: (test) stopped. 
(lldb) thread list 
Process 12087 stopped 
* thread #1: tid = 0x1066d3, 0x0000000100000f69 test`main(argc=1, argv=0x00007fff5fbff280) at main.m:5, queue = 'com.apple.main-thread', stop reason = step over 
    thread #2: tid = 0x106ab3, 0x00007fffc942c070 libsystem_pthread.dylib`start_wqthread 
    thread #3: tid = 0x106ab4, 0x00007fffc934244e libsystem_kernel.dylib`__workq_kernreturn + 10 
    thread #4: tid = 0x106ab5, 0x00007fffc8923e85 libobjc.A.dylib`class_createInstance + 142, queue = 'com.apple.root.default-qos.overcommit' 

现在有四个线程,并且其中一些停在初始化的中间。

但罗布,”你说,“当我在Xcode运行test和停止调用currentRunLoop之前,它已经拥有四个线程“如下所示:

debugging under Xcode

!‘的确如此,’我回答。如果您运行的菜单项调试>调试工作流程>共享库......,和类型的Xcode进入过滤器中,你可以发现为什么:

shared libraries from Xcode

当您运行的Xcode下的程序,Xcode中注入一些额外的共享库进入您的流程以提供额外的调试支持。这些共享库包括在代码运行之前运行的初始化代码,以及初始化代码对GCD执行某些操作,因此GCD在第一行代码运行之前被初始化(创建其线程池)。

工作队列根据工作负载调整其线程池的大小。由于没有任何内容将作业添加到队列中,因此它立即将其池缩小为只有一个后台线程。这就是为什么当您查看Xcode的CPU报告时,您只会看到两个线程:运行循环的主线程和等待作业运行的一个工作线程。

+0

谢谢您的详细解释!你怎么知道的?我找不到在苹果的信息( –

+0

我想通了通过调试在终端和一些猜测的考验。[这个页面](http://newosxbook.com/articles/GCD.html)有许多有趣的信息,但直到发布我的答案之后我才发现它。 –

相关问题