2013-04-08 35 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