2013-04-08 45 views
1

我想了解更多关于objective-c线程的知识,所以我做了一个测试程序,它只是循环输出循环的迭代。 但是,我得到的输出不是我所期望的。我有一个想法,为什么,但首先这里是我的代码:Objective-C线程

的main.m

#import <Foundation/Foundation.h> 
#import "Car.h" 


int main(int argc, const char * argv[]) 
{ 

    @autoreleasepool { 
     Car* myCar = [[Car new] autorelease]; 

     [myCar performSelectorInBackground:@selector(LoopAndSay) withObject:nil]; 

     for(int i = 0; i < 100; i++) 
     { 

      NSLog(@"Main loop on %i", i); 
     } 


    } 
return 0; 
} 

Car.m

#import "Car.h" 

@implementation Car 
@synthesize name, model; 

-(void) LoopAndSay { 

    for(int i = 0; i < 100; i++) 
    { 
     NSLog(@"Looping for the %i time", i); 

    } 

} 
@end 

现在,如果我运行它的背景是循环有时不会完成(在迭代94和97之间停止)。另外,如果我切换我的代码,以便在主线程循环之后不调用后台循环,那么它将不会运行任何迭代。 这是因为主线程已完成并且不想等待后台线程运行完成?如果是这样,有没有办法强制程序继续运行,直到主线程和后台线程都完成了?

回答

3

这几乎肯定是因为 在线程完成之前退出了自动释放池的范围 main函数在后台线程完成之前返回。尝试在结束之前添加sleep(3)或其他东西,看看您的后台线程是否完成。

在Mac OS X上,当所有“前景”线程完成时,进程终止。 peformSelectorInBackground:只会创建一个后台线程,因此一旦main返回,您就没有前台线程,并且进程终止。

+0

我还想补充说,一切从main.m开始执行如果它不是从main.m调用,或者从main.m调用的某些东西不调用你的函数,它将不会被执行。 – 2013-04-08 18:50:25

+0

我甚至没有考虑过在后台线程完成(甚至开始)之前退出autorelease池的范围。现在它变得更有意义。谢谢! – 2013-04-08 18:51:52

+0

@DanielMartin,但请阅读编辑。这不是因为你退出autorelease池的范围,这是因为你离开了'main'函数。 – zneak 2013-04-08 18:53:25

3

这是因为使用performSelectorInBackground:...和其他Objective-C API创建的所有线程都是分开的,因此程序可以在不等待它们完成的情况下终止。来自Threading Programming Guide

在应用程序退出时,分离的线程可以立即终止,但可连接的线程不能。 [...]如果你想创建可连接的线程,唯一的方法是使用POSIX线程...

在这种情况下,你的主线程循环恰好比背景快一点线程,所以后台线程循环不会运行到最后。您可以使用NSOperationQueue来代替使用POSIX线程(这非常不方便),这可以轻松地让您等待队列中的所有操作完成。

+0

我会查找NSOperationQueue,谢谢! – 2013-04-08 18:58:13