IOS多線程編程筆記與NSRunLoop學習

多線程與NSLoop筆記;
1.雖然operation objects和dispatch queue提供了更加現代化的多核併發操作,但mac os和iOS也提供直接操作和管理線程的接口,如果正在創建新的應用程序,蘋果建議我們使用gcd或operation objects;除此之外還有:
1)idle-time notifications,當前程序的run loop空閒時會發出該通知,適合處理一些低優先級的短作業;
2)調用系統提供的異步api,不需要自己去考慮線程層次的問題;
3)定時器;
4)分離的單獨進程;在某些時候需要使用,比如需要特定權限的作業可能需要另起進程。
2.mac os/ios中使用到的線程技術包括:
1)cocoa threads;這是oc的類庫,主要有NSThread類;
2)POSIX threads;這是c的函數庫,支持POSIX接口,POSIX標準定義了操作系統應該爲應用程序提供的接口標準,POSIX標準意在期望獲得源代碼級別的軟件可移植性。換句話說,爲一個POSIX兼容的操作系統編寫的程序,應該可以在任何其它的POSIX操作系統上編譯執行。POSIX並不侷限於UNIX。許多其它的操作系統,例如DEC OpenVMS支持POSIX標準;
3.一個run loop是用來在線程上管理事件異步到達的基礎設施。一個run loop爲線程監測一個或多個事件源。當事件到達的時候,系統喚醒線程並調度事件到run loop,然後分配給指定程序。如果沒有事件出現和準備處理,run loop把線程置於休眠狀態。配置run loop需要:
1)創建並啓動線程;
2)獲取run loop的對象引用;
3)設置事件處理程序,並告訴run loop運行;
4.cocoa會自動爲你的主線程配置run loop,如果你打算創建長時間運行的輔助線程,你必須爲你的線程配置相應的run loop。使用run loop 的目的是讓你的線程在有工作的時候忙於工作,而沒工作的時候處於休眠狀態。
5.run loop的管理並不完全自動,你仍然需要設計你的線程代碼在合適的時候啓動run loop並正確響應輸入事件。你的代碼要提供實現循環部分的控制語句,換言之就是要有while或for循環語句來驅動run loop。在你的循環中,使用run loop object來運行事件處理代碼,它響應接收到的事件並啓動已經安裝的處理程序。
6.僅當在爲你的程序創建輔助線程的時候,你纔可能需要顯式運行一個run loop,一般不需要使用,瞭解其概念即可,只有如下情況纔可能需要使用:
1)使用端口或自定義輸入源和其它線程通信;
2)使用線程的定時器;
3)Cocoa中使用任何performSelector…的方法;
4)使線程週期性工作;

7.總體而言Run loop和線程編程的內容比較難懂,可以在遇到維護類似代碼時,去參考蘋果的多線程編程文檔,新寫的代碼都不再使用之爲好,加上dispatch sources可代替Run loop的情況下,更加沒有必要使用之。NSRunLoop對象比CFRunLoop的c函數更加易於使用,可以獲取currentRunLoop並調用addPort:forMode或addTimer:forMode往它上面添加事件,不過它是非線程安全的,也就是不要在NSRunLoop所在的線程之外去獲取和改變其它屬性,可能結果無法預知。

8.簡單的runloop與thread的關係可以理解爲,runloop負責管理線程while循環中的部分代碼,線程在while中通過判斷runloop是否有輸入等的條件,runloop所封裝的代碼塊等來達到一直循環處理事件的效果,同時runloop在沒有事件時,也可以通知線程休眠。

【摘錄網上找到的資料,感覺比較能理解】RunLoop

RunLoop從字面上看是運行循環的意思,這一點也不錯,它確實就是一個循環的概念,或者準確的說是線程中的循環。 本文一開始就提到有些程序是一個圈,這個圈本質上就是這裏的所謂的RunLoop,就是一個循環,只是這個循環里加入很多特性。 
首先循環體的開始需要檢測是否有需要處理的事件,如果有則去處理,如果沒有則進入睡眠以節省CPU時間。 所以重點便是這個需要處理的事件,在RunLoop中,需要處理的事件分兩類,一種是輸入源,一種是定時器,定時器好理解就是那些需要定時執行的操作,輸 入源分三類:performSelector源,基於端口(Mach port)的源,以及自定義的源。編程的時候可以添加自己的源。RunLoop還有一個觀察者Observer的概念,可以往RunLoop中加入自己的 觀察者以便監控着RunLoop的運行過程,CFRunLoop.h中定義了所有觀察者的類型:

  1. enum CFRunLoopActivity { kCFRunLoopEntry = (1 << 0), kCFRunLoopBeforeTimers = (1 << 1), kCFRunLoopBeforeSources = ( 

如果你使用過select系統調用寫過程序你便可以快速的理解runloop事件源的概念,本質上講事件源的機制和select一樣是一種多路複用IO的 實現,在一個線程中我們需要做的事情並不單一,如需要處理定時鐘事件,需要處理用戶的觸控事件,需要接受網絡遠端發過來的數據,將這些需要做的事情統統注 冊到事件源中,每一次循環的開始便去檢查這些事件源是否有需要處理的數據,有的話則去處理。 拿具體的應用舉個例子,NSURLConnection網絡數據請求,默認是異步的方式,其實現原理就是創建之後將其作爲事件源加入到當前的 RunLoop,而等待網絡響應以及網絡數據接受的過程則在一個新創建的獨立的線程中完成,當這個線程處理到某個階段的時候比如得到對方的響應或者接受完 了網絡數據之後便通知之前的線程去執行其相關的delegate方法。所以在Cocoa中經常看到scheduleInRunLoop:forMode: 這樣的方法,這個便是將其加入到事件源中,當檢測到某個事件發生的時候,相關的delegate方法便被調用。對於CoreFoundation這一層而 言,通常的模式是創建輸入源,然後將輸入源通過CFRunLoopAddSource函數加入到RunLoop中,相關事件發生後,相關的回調函數會被調 用。如CFSocket的使用。 另外RunLoop中還有一個運行模式的概念,每一個運行循環必然運行在某個模式下,而模式的存在是爲了過濾事件源和觀察者的,只有那些和當前 RunLoop運行模式一致的事件源和觀察者纔會被激活。

每一個線程都有其對應的RunLoop,但是默認非主線程的RunLoop是沒有運行的,需要爲RunLoop添加至少一個事件源,然後去run它。一般情況下我們是沒有必要去啓用線程的RunLoop的,除非你在一個單獨的線程中需要長久的檢測某個事件。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章