一些相關總結(同步、異步、並行、串行概念,GCD、NSOperation對比)
1、進程與線程概念
2、多線程-GCD
3、多線程-NSOperation
4、多線程-NSThread
5、隊列概念
6、多線程面試題java
GCD --> iOS 4.0
(1)將任務(block)添加到隊列(串行/併發(全局)),指定執行任務的方法(同步(阻塞)/異步)
(2)拿到 dispatch_get_main_queue()。 線程間通訊
(3)NSOperation沒法作到一次性執行、延遲執行、調度組(op相對複雜)
(4)提供了更多的控制能力以及操做隊列中所不能使用的底層函數ios
NSOperation ----> iOS 2.0 (後來蘋果改造了NSOperation的底層)
(1)將操做(異步執行)添加到隊列(併發/全局)
(2)[NSOperationQueue mainQueue] 主隊列。 任務添加到主隊列, 就會在主線程執行
(3)提供了一些GCD很差實現的,」最大併發數「、依賴關係、暫停/繼續 --- 掛起、取消全部的任務git
對比:
(1)GCD是純C語言的API,NSOperationQueue是基於GCD的OC版本封裝
(2)GCD只支持FIFO的隊列,NSOperationQueue能夠很方便的調整執行順序、設置最大併發數量 (FIFO 就是先進先出)
(3)NSOperationQueue能夠很輕鬆的在Operation間設置依賴關係,而GCD須要寫不少代碼才能實現
(4)NSOperationQueue支持KVO(鍵值觀察者),能夠監聽operation是否正在執行 (isExecuted)、是否結束(isFinished)、是否取消(isCanceld)
(5)GCD的執行速度比NSOperationQueue快(封裝GCD,更高層的東西,性能很差,由於還要轉化成GCD)快程序員
在項目何時選擇使用GCD,何時選擇NSOperation?
· NSOperation:
任務之間有依賴\或者要監放任務的執行狀況
項目中使用的優勢是它是對線程的高度抽象,會使程序結構更好,子類化NSOperation的設計思路具備面向對象的優勢(複用、封裝),使得實現多線程支持,而接口簡單,建議在複雜項目中使用。
· GCD:
任務之間不太依賴 項目中使用GCD的優勢是GCD自己很是簡單、易用,對於不復雜的多線程操做,會節省代碼量,而Block參數的使用,會是代碼更爲易讀,建議在簡單項目中使用。github
進程百度百科面試
進程(Process)是計算機中的程序關於某數據集合上的一次運行活動,是系統進行資源分配和調度的基本單位,是操做系統結構的基礎。在早期面向進程設計的計算機結構中,進程是程序的基本執行實體;在當代面向線程設計的計算機結構中,進程是線程的容器。程序是指令、數據及其組織形式的描述,進程是程序的實體。objective-c
線程百度百科數據庫
線程,有時被稱爲輕量進程(Lightweight Process,LWP),是程序執行流的最小單元。一個標準的線程由線程ID,當前指令指針(PC),寄存器集合和堆棧組成。另外,線程是進程中的一個實體,是被系統獨立調度和分派的基本單位,線程本身不擁有系統資源,只擁有一點兒在運行中必不可少的資源,但它可與同屬一個進程的其它線程共享進程所擁有的所有資源。一個線程能夠建立和撤消另外一個線程,同一進程中的多個線程之間能夠併發執行。因爲線程之間的相互制約,導致線程在運行中呈現出間斷性。線程也有就緒、阻塞和運行三種基本狀態。就緒狀態是指線程具有運行的全部條件,邏輯上能夠運行,在等待處理機;運行狀態是指線程佔有處理機正在運行;阻塞狀態是指線程在等待一個事件(如某個信號量),邏輯上不可執行。每個程序都至少有一個線程,若程序只有一個線程,那就是程序自己。 線程是程序中一個單一的順序控制流程。進程內有一個相對獨立的、可調度的執行單元,是系統獨立調度和分派CPU的基本單位指令運行時的程序的調度單位。在單個程序中同時運行多個線程完成不一樣的工做,稱爲多線程。編程
進程總結c#
- 進程是指在系統中
正在運行
的一個應用程序- 每一個進程之間是
獨立
的,每一個進程均運行在其專用且受保護的內存空間內
線程總結
- 1個進程要想執行任務,
必須
得有線程(每1個進程至少要有一個線程
)線程是進程的基本執行單元
,一個進程的全部任務都在線程中執行
進程(process)是一塊包含了某些資源的內存區域。操做系統利用進程把它的工做劃分爲一些功能單元。進程中所包含的一個或多個執行單元稱爲線程(thread)。進程還擁有一個私有的虛擬地址空間,該空間僅能被它所包含的線程訪問。一般在一個進程中能夠包含若干個線程,它們能夠利用進程所擁有的資源。在引入線程的操做系統中,一般都是把進程做爲分配資源的基本單位,而把線程做爲獨立運行和獨立調度的基本單位。因爲線程比進程更小,基本上不擁有系統資源,故對它的調度所付出的開銷就會小得多,能更高效的提升系統內多個程序間併發執行的程度。簡而言之,一個程序至少有一個進程,一個進程至少有一個線程。一個程序就是一個進程,而一個程序中的多個任務則被稱爲線程。 線程只能歸屬於一個進程而且它只能訪問該進程所擁有的資源。當操做系統建立一個進程後,該進程會自動申請一個名爲主線程或首要線程的線程。應用程序(application)是由一個或多個相互協做的進程組成的。另外,進程在執行過程當中擁有獨立的內存單元,而多個線程共享內存,從而極大地提升了程序的運行效率。線程在執行過程當中與進程仍是有區別的。每一個獨立的線程有一個程序運行的入口、順序執行序列和程序的出口。可是線程不可以獨立執行,必須依存在應用程序中,由應用程序提供多個線程執行控制。 從邏輯角度來看,多線程的意義在於一個應用程序中,有多個執行部分能夠同時執行。但操做系統並無將多個線程看作多個獨立的應用,來實現進程的調度和管理以及資源分配。這就是進程和線程的重要區別。 進程是具備必定獨立功能的程序關於某個數據集合上的一次運行活動,進程是系統進行資源分配和調度的一個獨立單位。 線程是進程的一個實體,是CPU調度和分派的基本單位,它是比進程更小的能獨立運行的基本單位。線程本身基本上不擁有系統資源,只擁有一點在運行中必不可少的資源(如程序計數器,一組寄存器和棧),可是它可與同屬一個進程的其餘的線程共享進程所擁有的所有資源。
線程與進程對比?
簡而言之,一個程序至少有一個進程,一個進程至少有一個線程(即主線程)。一個程序就是一個進程,而一個程序中的多個任務則被稱爲線程。
學習多線程,先了解手機裏有幾個重要的芯片:
主芯片:CPU(雙核)+GPU(至關於電腦裏的顯卡)
內存(RAM):至關於電腦的內存條
閃存芯片:相於於電腦的硬盤
電源管理芯片
藍牙、wifi、gps芯片
多線程應用:
耗時操做(數據庫中的讀取,圖片的處理(濾鏡) )
進程是來幫你分配內存的
多線程開線程通常五條之內
全稱Grand Central Dispatch,純C語言,提供了很是多強大的函數
優點:
GCD中2個核心概念:
GCD的使用就兩個步驟:
隊列的類型: GCD的隊列能夠分爲兩種類型:
· 併發隊列
(1) 隊列中的任務 一般 會併發執行
(2) 可讓多個任務併發(同時)執行(自動開啓多個線程同時執行任務)
(3) 併發功能只有在異步(dispatch_async)函數下才有效
· 串行隊列:
(1) 隊列中的任務 只 會順序執行
(2) 讓任務一個接一個的執行(一個任務執行完畢後,再執行下一個任務)
GCD內部是怎麼實現的? (1) iOS和OS X的核心是XNU內核,GCD是基於XNU內核實現的
(2) GCD的API所有在libdispatch庫中
(3) GCD底層實現主要有Dispatch Queue和Dispatch Source · Dispatch Queue: 管理block(操做) · Dispatch Source :處理事件(MACH端口發送,MACH端口接收,檢測與進程相關事件等10種事件)
dispatch_queue_t q = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_queue_t q = dispatch_queue_create("queuename", DISPATCH_QUEUE_CONCURRENT);
dispatch_queue_t t = dispatch_queue_create("queuename",DISPATCH_QUEUE_SERIAL);
// 實例化一個調度組
dispatch_group_t group = dispatch_group_create();
// 隊列
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
// 任務添加到隊列queue
dispatch_group_async(group, queue, ^{
NSLog(@"下載小說A---%@", [NSThread currentThread]);
});
dispatch_group_async(group, queue, ^{
NSLog(@"下載小說B---%@", [NSThread currentThread]);
});
dispatch_group_async(group, queue, ^{
NSLog(@"下載小說X---%@", [NSThread currentThread]);
});
// 得到全部調度組裏面的異步任務完成的通知
// dispatch_group_notify(group, queue, ^{
// NSLog(@"下載完成,請觀看%@", [NSThread currentThread]); // 異步的
// });
//注意點: 在調度組完成通知裏,能夠跨隊列通訊
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
// 更新UI,在主線程
NSLog(@"下載完成,請觀看%@", [NSThread currentThread]); // 異步的
});
複製代碼
dispatch_group_enter
: 通知 group,下個任務要放入 group 中執行了 dispatch_group_leave
: 通知 group,任務成功完成,要移除,與 enter成對出現 dispatch_group_wait
: 在任務組完成時調用,或者任務組超時是調用(完成指的是enter和leave次數同樣多)
dispatch_group_notify
: 只要任務所有完成了,就會在最後調用
- (void)gcdGroupEnterAndLeave {
dispatch_group_t group = dispatch_group_create();
dispatch_group_enter(group);
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// 請求1
[網絡請求:{
成功:dispatch_group_leave(group);
失敗:dispatch_group_leave(group);
}];
});
dispatch_group_enter;
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// 請求2
[網絡請求:{
成功:dispatch_group_leave;
失敗:dispatch_group_leave;
}];
});
dispatch_group_enter(group);
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// 請求3
[網絡請求:{
成功:dispatch_group_leave(group);
失敗:dispatch_group_leave(group);
}];
});
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
// 界面刷新
NSLog(@"任務均完成,刷新界面");
});
}
複製代碼
首先是 Apple Documentation 對dispatch_barrier_async的解釋
dispatch barrier容許開發者在一個並行隊列中創造一個同步點,其實也是用於在競爭條件下資源的保護,防止同一資源同時被使用。 在並行異步任務中: barrier_sync前的任務併發執行,syncbarrier後的任務必須等syncbarrier中的任務執行完成以後纔會執行他們,也會阻塞主線程的任務
barrier_async前的任務併發執行,barrier_async後的任務必須等barrier_async中的任務執行完成以後纔會執行他們,可是Barrier不能阻塞主線程的任務
做用如:打造線程安全的 NSMutableArray NSMutableArray自己是線程不安全的。簡單來講,線程安全就是多個線程訪問同一段代碼,程序不會異常、不Crash。而編寫線程安全的代碼主要依靠線程同步。 一、不使用atomic修飾屬性打造線程安全的緣由: 1 ) atomic 的內存管理語義是原子性的,僅保證了屬性的setter和getter方法是原子性的,是線程安全的,可是屬性的其餘方法,如數組添加/移除元素等並非原子操做,因此不能保證屬性是線程安全的。 2 ) atomic雖然保證了getter、setter方法線程安全,可是付出的代價很大,執行效率要比nonatomic慢不少倍(有說法是慢10-20倍)。 總之:使用nonatomic修飾NSMutableArray對象就能夠了,而使用鎖、dispatch_queue來保證NSMutableArray對象的線程安全。 二、打造線程安全的NSMutableArray 在《Effective Objective-C 2.0..》書中第41條:多用派發隊列,少用同步鎖中指出:使用「串行同步隊列」(serial synchronization queue),將讀取操做及寫入操做都安排在同一個隊列裏,便可保證數據同步。而經過併發隊列,結合GCD的柵欄塊(barrier)來不只實現數據同步線程安全,還比串行同步隊列方式更高效。
在主隊列開啓異步任務,不會開啓新的線程而是依然在主線程中執行代碼塊中的代碼。爲何不會阻塞線程? 主隊列開啓異步任務,雖然不會開啓新的線程,可是他會把異步任務下降優先級,等閒着的時候,就會在主線程上執行異步任務。
在主隊列開啓同步任務,爲何會阻塞線程? 在主隊列開啓同步任務,由於主隊列是串行隊列,裏面的線程是有順序的,先執行完一個線程才執行下一個線程,而主隊列始終就只有一個主線程,主線程是不會執行完畢的,由於他是無限循環的,除非關閉應用程序。所以在主線程開啓一個同步任務,同步任務會想搶佔執行的資源,而主線程任務一直在執行某些操做,不願放手。兩個的優先級都很高,最終致使死鎖,阻塞線程了。
主線程隊列注意: 下面代碼執行順序 1111 2222
- (void)main_queue_deadlock {
dispatch_queue_t q = dispatch_get_main_queue();
NSLog(@"1111");
dispatch_async(q, ^{
NSLog(@"主隊列異步 %@", [NSThread currentThread]);
});
NSLog(@"2222");
// 下面會形成線程死鎖
// dispatch_sync(q, ^{
// NSLog(@"主隊列同步 %@", [NSThread currentThread]);
// });
}
複製代碼
dispatch_queue_t q = dispatch_queue_create("test", DISPATCH_QUEUE_SERIAL);
dispatch_async(q, ^{
NSLog(@"異步任務 %@", [NSThread currentThread]);
// 下面開啓同步形成死鎖:由於串行隊列中線程是有執行順序的,須要等上面開啓的異步任務執行完畢,纔會執行下面開啓的同步任務。而上面的異步任務還沒執行完,要到下面的大括號纔算執行完畢,而下面的同步任務已經在搶佔資源了,就會發生死鎖。
dispatch_sync(q, ^{
NSLog(@"同步任務 %@", [NSThread currentThread]);
});
});
複製代碼
dispatch_queue_t q = dispatch_queue_create("test", DISPATCH_QUEUE_SERIAL);
dispatch_sync(q, ^{
NSLog(@"同步任務 %@", [NSThread currentThread]);
// 下面開啓同步形成死鎖:由於串行隊列中線程是有執行順序的,須要等上面開啓的同步任務執行完畢,纔會執行下面開啓的同步任務。而上面的同步任務還沒執行完,要到下面的大括號纔算執行完畢,而下面的同步任務已經在搶佔資源了,就會發生死鎖。
dispatch_sync(q, ^{
NSLog(@"同步任務 %@", [NSThread currentThread]);
});
});
NSLog(@"同步任務 %@", [NSThread currentThread]);
複製代碼
dispatch_queue_t q = dispatch_queue_create("test", DISPATCH_QUEUE_CONCURRENT);
// 任務嵌套
dispatch_sync(q, ^{
NSLog(@"1 %@", [NSThread currentThread]);
dispatch_sync(q, ^{
NSLog(@"2 %@", [NSThread currentThread]);
dispatch_sync(q, ^{
NSLog(@"3 %@", [NSThread currentThread]);
});
});
dispatch_async(q, ^{
NSLog(@"4 %@", [NSThread currentThread]);
});
NSLog(@"5 %@", [NSThread currentThread]);
});
// 運行結果是: 12345 或12354
複製代碼
並行隊列裏開啓同步任務是有執行順序的,只有異步纔沒有順序
串行隊列開啓異步任務,是有順序的
// 建立隊列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
// 建立3個操做
NSOperation *a = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"operationA---");
}];
NSOperation *b = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"operationB---");
}];
NSOperation *c = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"operationC---");
}];
// 添加依賴
[c addDependency:a];
[c addDependency:b];
// 執行操做
[queue addOperation:a];
[queue addOperation:b];
[queue addOperation:c];
複製代碼
存放NSOperation的集合類。
(1) 用來存放NSOperation對象的隊列,能夠用來異步執行一些操做
(2) 通常能夠用在網絡請求等耗時操做
解釋:操做和操做隊列,基本能夠當作java中的線程和線程池的概念。用於處理ios多線程開發的問題。網上部分資料提到一點是,雖然是queue,可是卻並非帶有隊列的概念,放入的操做並不是是按照嚴格的先進現出。
這邊又有個疑點是,對於隊列來講,先進先出的概念是Afunc添加進隊列,Bfunc緊跟着也進入隊列,Afunc先執行這個是必然的,可是Bfunc是等Afunc徹底操做完之後,B纔開始啓動而且執行,所以隊列的概念離亂上有點違背了多線程處理這個概念。可是轉念一想其實能夠參考銀行的取票和叫號系統。所以對於A比B先排隊取票可是B率先執行完操做,咱們亦然能夠感性認爲這仍是一個隊列。可是後來看到一票關於這操做隊列話題的文章,其中有一句提到「由於兩個操做提交的時間間隔很近,線程池中的線程,誰先啓動是不定的。」瞬間以爲這個queue名字有點忽悠人了,還不如pool~綜合一點,咱們知道他能夠比較大的用處在於能夠幫組多線程編程就行了。
// 建立線程的方式1
- (void)createThread1 {
// 建立線程
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(download:) object:@"http://a.png"];
thread.name = @"下載線程";
// 啓動線程(調用self的download方法)
[thread start];
}
// 建立線程的方式2
- (void)createThread2 {
[NSThread detachNewThreadSelector:@selector(download:) toTarget:self withObject:@"http://b.jpg"];
}
// 建立線程的方式3
- (void)createThread3 {
// 這2個不會建立線程,在當前線程中執行
// [self performSelector:@selector(download:) withObject:@"http://c.gif"];
// [self download:@"http://c.gif"];
[self performSelectorInBackground:@selector(download:) withObject:@"http://c.gif"];
}
複製代碼
-(void)threadSafe {
self.leftTicketCount = 50;
self.thread1 = [[NSThread alloc] initWithTarget:self selector:@selector(saleTicket) object:nil];
self.thread1.name = @"1號窗口";
self.thread2 = [[NSThread alloc] initWithTarget:self selector:@selector(saleTicket) object:nil];
self.thread2.name = @"2號窗口";
self.thread3 = [[NSThread alloc] initWithTarget:self selector:@selector(saleTicket) object:nil];
self.thread3.name = @"3號窗口";
[self threadSafeStart];
}
- (void)threadSafeStart {
[self.thread1 start];
[self.thread2 start];
[self.thread3 start];
}
// 賣票
- (void)saleTicket {
while (1) {
// ()小括號裏面放的是鎖對象
@synchronized(self) { // 開始加鎖
int count = self.leftTicketCount;
if (count > 0) {
[NSThread sleepForTimeInterval:0.05];
self.leftTicketCount = count - 1;
NSLog(@"%@賣了一張票, 剩餘%d張票", [NSThread currentThread].name, self.leftTicketCount);
} else {
return; // 退出循環
}
} // 解鎖
}
}
複製代碼
主線程 每個應用程序都只有一個主線程。
全部UI的更新工做,都必須在主線程上執行! 主線程是一直工做的,並且除非將程序殺掉,不然主線程的工做永遠不會結束!
隊列和線程的區別:
隊列是管理線程的,至關於線程池,能管理線程何時執行。
隊列分爲串行隊列和並行隊列:
串行隊列:隊列中的線程按順序執行(不會同時執行)
並行隊列:隊列中的線程會併發執行,可能會有一個疑問,隊列不是先進先出嗎,若是後面的任務執行完了,怎麼出去的了。這裏須要強調下,任務執行完畢了,不必定出隊列。只有前面的任務執行完了,纔會出隊列,也就是說你即便執行完畢了,也必須等前面的任務執行完畢出隊列,才能夠出去。
主線程和工做線程的區別:
主線程: 系統自動建立 能直操做UI 不能作耗時比較多的操做 自帶自動釋放池 RunLoop自動運行
工做線程:程序猿手工建立 不能直接操做UI 寫死循環都行 須要手工寫自動釋放池 手動運行
主線程隊列和GCD建立的隊列區別: 主線程隊列:主線程隊列中不能開啓同步,會阻塞主線程。只能開啓異步任務,開啓異步任務也不會開啓新的線程,只是下降異步任務的優先級,讓cpu空閒的時候纔去調用。而同步任務,會搶佔主線程的資源,會形成死鎖。 GCD建立的隊列:在GCD中建立的隊列優先級沒有主隊列高,因此在GCD中的串行隊列開啓同步任務裏面沒有嵌套任務是不會阻塞主線程,只有一種可能致使死鎖,就是串行隊列裏,嵌套開啓任務,有可能會致使死鎖。
同步與異步的區別: 同步任務優先級高,在線程中有執行順序,不會開啓新的線程。 異步任務優先級低,在線程中執行沒有順序,看cpu閒不閒。在主隊列中不會開啓新的線程,其餘隊列會開啓新的線程。
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// 下載圖片
UIImage *image = nil;
dispatch_async(dispatch_get_main_queue(), ^{
// 回到主線程
});
// [self performSelector:@selector(settingImage:) onThread:[NSThread mainThread] withObject:image waitUntilDone:YES modes:nil];
// [self performSelectorOnMainThread:@selector(settingImage:) withObject:image waitUntilDone:YES];
});
複製代碼
- (void)performSelector:(SEL)aSelector withObject:(nullable id)anArgument afterDelay:(NSTimeInterval)delay;
函數內部是經過NSTimer定時器實現,在NSRunLoop沒有開啓的狀況下,NSTimer不會獲得正常運行。dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self performSelector:@selector(fireBlock:) withObject:^{
NSLog(@"hello world");
} afterDelay:0.3];
});
複製代碼
[self performSelectorOnMainThread: withObject: waitUntilDone:];
[self performSelector: onThread:[NSThread mainThread] withObject: waitUntilDone:];
dispatch_async(dispatch_get_main_queue(), ^{
});
複製代碼
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){
});
[self performSelector: withObject: afterDelay:];
[NSTimer scheduledTimerWithTimeInterval: target: selector: userInfo: repeats:];
複製代碼
GCD怎麼用的? 全局隊列異步操做,會新建多個子線程,操做無序執行,若是隊列前有其餘任務,會等待其餘任務執行完畢在調用; 全局隊列同步操做,不會新建線程,順序執行; 主隊列全部的操做都是主線程順序執行,沒有異步概念,主隊列添加的同步操做永遠不會執行,會死鎖; 串行隊列添加的同步操做會死鎖,可是會執行嵌套同步操做以前的代碼; 並行隊列添加的同步操做不會死鎖都在主線程執行; 全局隊列添加的同步操做不會死鎖; 同步操做 最主要的目的,阻塞並行隊列任務的執行,只有當前的同步任務執行完畢以後,後邊的任務纔會執行,應用:用戶登陸。
多線程安全怎麼控制:
@synchronized @synchronized 的做用是建立一個互斥鎖,保證此時沒有其它線程對self對象進行修改。這個是objective-c的一個鎖定令牌,防止self對象在同一時間內被其它線程訪問,起到線程的保護做用。 通常在公用變量的時候使用,如單例模式或者操做類的static變量中使用。
NSLock 從微觀上看一個線程在CPU上走走停停的,其運行狀態能夠分爲(經典)三種:運行狀態、就緒狀態、阻塞。 兩個線程同時訪問一個共享的變量,一個對其加一、一個對其減1 因爲內存的速度遠低於CPU的速度,因此在設計CPU時一般不容許直接對內存中的數據進行運行。若是要運算內存中的數據一般是用一條CPU指令把內存中的數據讀入CPU、再用另一CPU指令對CPU中的數據作運算、最後再用一條CPU指令把結果寫回內存。 i++ 讀數據 運算 寫數據 因爲CPU在執行兩條指令中間能夠被打斷,就可能致使另外一個訪問一樣內存的線程運行,最終致使運算結果出錯 解決辦法就是加線程鎖 NSLock lock方法 加鎖:若是這個沒被鎖上則直接上鎖、若是鎖已經被其它線程鎖上了當前線程就阻塞直至這個鎖被其它線程解鎖 unlock方法 解鎖:解開這個鎖,若是有其它線程由於等這個鎖而進入了阻塞狀態還要把那個線程變成就緒 用lock保護共享數據的原理 先上鎖 訪問共享的數據(臨界區) 解鎖
NSCondition 線程的同步,有一個經典的生產者消費者問題: 好比一個線程A負責下載數據 另外一個線程B負責處理數據 還有一個線程C負責顯示 解決方法就是用NSCondition: lock wait signal unlock 產生者線程(產生數據的線程),生產數據以後: lock signal(發出信號:若是有其它線程在等待這個信號就把那個線程變爲就緒狀態) unlock 消費者線程(處理或使用數據的線程): lock wait(等待信號:若是有線程發信號當前線程就會進入阻塞狀態、直到有線程發出信號) unlock NSCondition有一個問題:假喚醒(wait的時候明明沒有線程發信號,wait也可能返回),一般用一個表示狀態的變量就能解決這個問題
不可改變的對象,一般是線程安全的 線程安全的類和函數: NSArray, NSData, NSNumber..... 非線程安全: NSBundle, NSCoder, NSArchiver, NSMutableArray
列舉幾種進程的同步機制,並比較其優缺點。 答案:原子操做、信號量機制、自旋鎖、管程、會合、分佈式系統
進程之間通訊的途徑 答案:共享存儲系統消息傳遞系統管道:以文件系統爲基礎
進程死鎖的緣由 答案:資源競爭及進程推動順序非法
死鎖的4個必要條件 答案:互斥、請求保持、不可剝奪、環路
死鎖的處理 答案:鴕鳥策略、預防策略、避免策略、檢測與解除死鎖