iOS併發編程指南(3)

Dispatch Sources node

現代系統一般提供異步接口,容許應用向系統提交請求,而後在系統處理請求時應用能夠繼續處理本身的事情。Grand Central Dispatch正是基於這個基本行爲而設計,容許你提交請求,並經過block和dispatch queue報告結果。 編程

dispatch source是基礎數據類型,協調特定底層系統事件的處理。Grand Central Dispatch支持如下dispatch source: 服務器

Timer dispatch source:按期產生通知 網絡

Signal dispatch source:UNIX信號到達時產生通知 數據結構

Descriptor dispatch source:各類文件和socket操做的通知 併發

數據可讀 app

數據可寫 異步

文件在文件系統中被刪除、移動、重命名 socket

文件元數據信息改變 async

Process dispatch source:進程相關的事件通知

當進程退出時

當進程發起fork或exec等調用

信號被遞送到進程

Mach port dispatch source:Mach相關事件的通知

Custom dispatch source:你本身定義並本身觸發

Dispatch source替代了異步回調函數,來處理系統相關的事件。當你配置一個dispatch source時,你指定要監測的事件、dispatch queue、以及處理事件的代碼(block或函數)。當事件發生時,dispatch source會提交你的block或函數到指定的queue去執行

和手工提交到queue的任務不一樣,dispatch source爲應用提供連續的事件源。除非你顯式地取消,dispatch source會一直保留與dispatch queue的關聯。只要相應的事件發生,就會提交關聯的代碼到dispatch queue去執行。

爲了防止事件積壓到dispatch queue,dispatch source實現了事件合併機制。若是新事件在上一個事件處理器出列並執行以前到達,dispatch source會將新舊事件的數據合併。根據事件類型的不一樣,合併操做可能會替換舊事件,或者更新舊事件的信息。

建立Dispatch Source

建立dispatch source須要同時建立事件源和dispatch source自己。事件源是處理事件所須要的native數據結構,例如基於描述符的dispatch source,你須要打開描述符;基於進程的事件,你須要得到目標程序的進程ID。

而後能夠以下建立相應的dispatch source:

使用 dispatch_source_create 函數建立dispatch source

配置dispatch source:

爲dispatch source設置一個事件處理器

對於定時器源,使用 dispatch_source_set_timer 函數設置定時器信息

爲dispatch source賦予一個取消處理器(可選)調用 dispatch_resume 函數開始處理事件因爲dispatch source必須進行額外的配置才能被使用,dispatch_source_create 函數返回的dispatch source將處於掛起狀態。此時dispatch source會接收事件,可是不會進行處理。這時候你能夠安裝事件處理器,並執行額外的配置。

編寫和安裝一個事件處理器

你須要定義一個事件處理器來處理事件,能夠是函數或block對象,並使用 dispatch_source_set_event_handler 或 dispatch_source_set_event_handler_f 安裝事件處理器。事件到達時,dispatch source會提交你的事件處理器到指定的dispatch queue,由queue執行事件處理器。

事件處理器的代碼負責處理全部到達的事件。若是事件處理器已經在queue中並等待處理已經到達的事件,若是此時又來了一個新事件,dispatch source會合並這兩個事件。事件處理器一般只能看到最新事件的信息,不過某些類型的dispatch source也能得到已經發生以及合併的事件信息。

若是事件處理器已經開始執行,一個或多個新事件到達,dispatch source會保留這些事件,直到前面的事件處理器完成執行。而後以新事件再次提交處理器到queue。

函數事件處理器有一個context指針指向dispatch source對象,沒有返回值。Block事件處理器沒有參數,也沒有返回值。

 
  1. // Block-based event handler  
  2. void (^dispatch_block_t)(void)  
  3.    
  4. // Function-based event handler  
  5. void (*dispatch_function_t)(void *)  

在事件處理器中,你能夠從dispatch source中得到事件的信息,函數處理器能夠直接使用參數指針,Block則必須本身捕獲到dispatch source指針,通常block定義時會自動捕獲到外部定義的全部變量。

 
  1. dispatch_source_t source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, 
  2.                                  myDescriptor, 0, myQueue); 
  3. dispatch_source_set_event_handler(source, ^{ 
  4.    // Get some data from the source variable, which is captured 
  5.    // from the parent context. 
  6.    size_t estimated = dispatch_source_get_data(source); 
  7.   
  8.    // Continue reading the descriptor... 
  9. }); 
  10. dispatch_resume(source); 

Block捕獲外部變量容許更大的靈活性和動態性。固然,在Block中這些變量默認是隻讀的,雖然可使用__block來修改捕獲的變量,可是你最好不要在事件處理器中這樣作。由於Dispatch source異步執行事件處理器,當事件處理器修改原始外部變量時,有可能這些變量已經不存在了。

下面是事件處理器可以得到的事件信息:

函數 描述
dispatch_source_get_handle 這個函數返回dispatch source管理的底層系統數據類型。

對於描述符dispatch source,函數返回一個int,表示關聯的描述符

對於信號dispatch source,函數返回一個int,表示最新事件的信號數值

對於進程dispatch source,函數返回一個pid_t數據結構,表示被監控的進程

對於Mach port dispatch source,函數返回一個 mach_port_t 數據結構

對於其它dispatch source,函數返回的值未定義
dispatch_source_get_data 這個函數返回事件關聯的全部未決數據。

對於從文件中讀取數據的描述符dispatch source,這個函數返回能夠讀取的字節數

對於向文件中寫入數據的描述符dispatch source,若是能夠寫入,則返回正數值

對於監控文件系統活動的描述符dispatch source,函數返回一個常量,表示發生的事件類型,參考 dispatch_source_vnode_flags_t 枚舉類型

對於進程dispatch source,函數返回一個常量,表示發生的事件類型,參考 dispatch_source_proc_flags_t 枚舉類型

對於Mach port dispatch source,函數返回一個常量,表示發生的事件類型,參考 dispatch_source_machport_flags_t 枚舉類型

對於自定義dispatch source,函數返回從現有數據建立的新數據,以及傳遞給 dispatch_source_merge_data 函數的新數據。
dispatch_source_get_mask 這個函數返回用來建立dispatch source的事件標誌

對於進程dispatch source,函數返回dispatch source接收到的事件掩碼,參考 dispatch_source_proc_flags_t 枚舉類型

對於發送權利的Mach port dispatch source,函數返回指望事件的掩碼,參考 dispatch_source_mach_send_flags_t 枚舉類型

對於自定義 「或」 的dispatch source,函數返回用來合併數據值的掩碼。

安裝一個取消處理器

取消處理器在dispatch soruce釋放以前執行清理工做。多數類型的dispatch source不須要取消處理器,除非你對dispatch source有自定義行爲須要在釋放時執行。可是使用描述符或Mach port的dispatch source必須設置取消處理器,用來關閉描述符或釋放Mach port。不然可能致使微妙的bug,這些結構體會被系統其它部分或你的應用在不經意間重用。

你能夠在任什麼時候候安裝取消處理器,但一般咱們在建立dispatch source時就會安裝取消處理器。使用 dispatch_source_set_cancel_handler 或 dispatch_source_set_cancel_handler_f 函數來設置取消處理器。

下面取消處理器關閉描述符:

 
  1. dispatch_source_set_cancel_handler(mySource, ^{ 
  2.    close(fd); // Close a file descriptor opened earlier. 
  3. }); 

修改目標Queue

在建立dispatch source時能夠指定一個queue,用來執行事件處理器和取消處理器。不過你也可使用 dispatch_set_target_queue 函數在任什麼時候候修改目標queue。修改queue能夠改變執行dispatch source事件的優先級。

修改dispatch source的目標queue是異步操做,dispatch source會盡量快地完成這個修改。若是事件處理器已經進入queue並等待處理,它會繼續在原來的Queue中執行。隨後到達的全部事件的處理器都會在後面修改的queue中執行。

關聯自定義數據到dispatch source

和Grand Central Dispatch的其它類型同樣,你可使用 dispatch_set_context 函數關聯自定義數據到dispatch source。使用context指針存儲事件處理器須要的任何數據。若是你在context指針中存儲了數據,你就應該安裝一個取消處理器,在dispatch source再也不須要時釋放這些context自定義數據。

若是你使用block實現事件處理器,你也能夠捕獲本地變量,並在Block中使用。雖然這樣也能夠代替context指針,可是你應該明智地使用Block捕獲變量。由於dispatch source長時間存在於應用中,Block捕獲指針變量時必須很是當心,由於指針指向的數據可能會被釋放,所以須要複製數據或retain。無論使用哪一種方法,你都應該提供一個取消處理器,在最後釋放這些數據。

Dispatch Source的內存管理

Dispatch Source也是引用計數的數據類型,初始計數爲1,可使用 dispatch_retain 和 dispatch_release 函數來增長和減小引用計數。引用計數到達0時,系統自動釋放dispatch source數據結構。

dispatch source的全部權能夠由dispatch source內部或外部進行管理。外部全部權時,另外一個對象擁有dispatch source,並負責在不須要時釋放它。內部全部權時,dispatch source本身擁有本身,並負責在適當的時候釋放本身。雖然外部全部權很經常使用,當你但願建立自主dispatch source,並讓它本身管理本身的行爲時,可使用內部全部權。例如dispatch source應用單一全局事件時,可讓它本身處理該事件,並當即退出。

Dispatch Source示例

建立一個定時器

定時器dispatch source定時產生事件,能夠用來發起定時執行的任務,如遊戲或其它圖形應用,可使用定時器來更新屏幕或動畫。你也能夠設置定時器,並在固定間隔事件中檢查服務器的新信息。

全部定時器dispatch source都是間隔定時器,一旦建立,會按你指定的間隔按期遞送事件。你須要爲定時器dispatch source指定一個指望的定時器事件精度,也就是leeway值,讓系統可以靈活地管理電源並喚醒內核。例如系統可使用leeway值來提早或延遲觸發定時器,使其更好地與其它系統事件結合。建立本身的定時器時,你應該儘可能指定一個leeway值。

就算你指定leeway值爲0,也不要指望定時器可以按照精確的納秒來觸發事件。系統會盡量地知足你的需求,可是沒法保證徹底精確的觸發時間。

當計算機睡眠時,定時器dispatch source會被掛起,稍後系統喚醒時,定時器dispatch source也會自動喚醒。根據你提供的配置,暫停定時器可能會影響定時器下一次的觸發。若是定時器dispatch source使用 dispatch_time 函數或 DISPATCH_TIME_NOW 常量設置,定時器dispatch source會使用系統默認時鐘來肯定什麼時候觸發,可是默認時鐘在計算機睡眠時不會繼續。

若是你使用 dispatch_walltime 函數來設置定時器dispatch source,則定時器會根據掛鐘時間來跟蹤,這種定時器比較適合觸發間隔相對比較大的場合,能夠防止定時器觸發間隔出現太大的偏差。

下面是定時器dispatch source的一個例子,每30秒觸發一次,leeway值爲1,由於間隔相對較大,使用 dispatch_walltime 來建立定時器。定時器會當即觸發第一次,隨後每30秒觸發一次。 MyPeriodicTask 和 MyStoreTimer 是自定義函數,用於實現定時器的行爲,並存儲定時器到應用的數據結構。

 
  1. dispatch_source_t CreateDispatchTimer(uint64_t interval, 
  2.               uint64_t leeway, 
  3.               dispatch_queue_t queue, 
  4.               dispatch_block_t block) 
  5.    dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 
  6.                                                      0, 0, queue); 
  7.    if (timer) 
  8.    { 
  9.       dispatch_source_set_timer(timer, dispatch_walltime(NULL, 0), interval, leeway); 
  10.       dispatch_source_set_event_handler(timer, block); 
  11.       dispatch_resume(timer); 
  12.    } 
  13.    return timer; 
  14.   
  15. void MyCreateTimer() 
  16.    dispatch_source_t aTimer = CreateDispatchTimer(30ull * NSEC_PER_SEC, 
  17.                                1ull * NSEC_PER_SEC, 
  18.                                dispatch_get_main_queue(), 
  19.                                ^{ MyPeriodicTask(); }); 
  20.   
  21.    // Store it somewhere for later use. 
  22.     if (aTimer) 
  23.     { 
  24.         MyStoreTimer(aTimer); 
  25.     } 

雖然定時器dispatch source是接收時間事件的主要方法,你還可使用其它選擇。若是想在指定時間間隔後執行一個block,可使用 dispatch_after 或 dispatch_after_f 函數。這兩個函數很是相似於dispatch_async,可是隻容許你指定一個時間值,時間一到就自動提交block到queue中執行,時間值能夠指定爲相對或絕對時間。

從描述符中讀取數據

要從文件或socket中讀取數據,須要打開文件或socket,並建立一個 DISPATCH_SOURCE_TYPE_READ 類型的dispatch source。你指定的事件處理器必須可以讀取和處理描述符中的內容。對於文件,須要讀取文件數據,併爲應用建立適當的數據結構;對於網絡socket,須要處理最新接收到的網絡數據。

讀取數據時,你老是應該配置描述符使用非阻塞操做,雖然你可使用 dispatch_source_get_data 函數查看當前有多少數據可讀,但在你調用它和實際讀取數據之間,可用的數據數量可能會發生變化。若是底層文件被截斷,或發生網絡錯誤,從描述符中讀取會阻塞當前線程,中止在事件處理器中間並阻止dispatch queue去執行其它任務。對於串行queue,這樣還可能會死鎖,即便是併發queue,也會減小queue可以執行的任務數量。

下面例子配置dispatch source從文件中讀取數據,事件處理器讀取指定文件的所有內容到緩衝區,並調用一個自定義函數來處理這些數據。調用方可使用返回的dispatch source在讀取操做完成以後,來取消這個事件。爲了確保dispatch queue不會阻塞,這裏使用了fcntl函數,配置文件描述符執行非阻塞操做。dispatch source安裝了取消處理器,確保最後關閉了文件描述符。

 
  1. dispatch_source_t ProcessContentsOfFile(const char* filename) 
  2.    // Prepare the file for reading. 
  3.    int fd = open(filename, O_RDONLY); 
  4.    if (fd == -1) 
  5.       return NULL; 
  6.    fcntl(fd, F_SETFL, O_NONBLOCK);  // Avoid blocking the read operation 
  7.   
  8.    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 
  9.    dispatch_source_t readSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, 
  10.                                    fd, 0, queue); 
  11.    if (!readSource) 
  12.    { 
  13.       close(fd); 
  14.       return NULL; 
  15.    } 
  16.   
  17.    // Install the event handler 
  18.    dispatch_source_set_event_handler(readSource, ^{ 
  19.       size_t estimated = dispatch_source_get_data(readSource) + 1; 
  20.       // Read the data into a text buffer. 
  21.       char* buffer = (char*)malloc(estimated); 
  22.       if (buffer) 
  23.       { 
  24.          ssize_t actual = read(fd, buffer, (estimated)); 
  25.          Boolean done = MyProcessFileData(buffer, actual);  // Process the data. 
  26.   
  27.          // Release the buffer when done. 
  28.          free(buffer); 
  29.   
  30.          // If there is no more data, cancel the source. 
  31.          if (done) 
  32.             dispatch_source_cancel(readSource); 
  33.       } 
  34.     }); 
  35.   
  36.    // Install the cancellation handler 
  37.    dispatch_source_set_cancel_handler(readSource, ^{close(fd);}); 
  38.   
  39.    // Start reading the file. 
  40.    dispatch_resume(readSource); 
  41.    return readSource; 

在這個例子中,自定義的 MyProcessFileData 函數肯定讀取到足夠的數據,返回YES告訴dispatch source讀取已經完成,能夠取消任務。一般讀取描述符的dispatch source在還有數據可讀時,會重複調度事件處理器。若是socket鏈接關閉或到達文件末尾,dispatch source自動中止調度事件處理器。若是你本身肯定再也不須要dispatch source,也能夠手動取消它。

向描述符寫入數據

向文件或socket寫入數據很是相似於讀取數據,配置描述符爲寫入操做後,建立一個 DISPATCH_SOURCE_TYPE_WRITE 類型的dispatch source,建立好以後,系統會調用事件處理器,讓它開始向文件或socket寫入數據。當你完成寫入後,使用 dispatch_source_cancel 函數取消dispatch source。

寫入數據也應該配置文件描述符使用非阻塞操做,雖然 dispatch_source_get_data 函數能夠查看當前有多少可用寫入空間,但這個值只是建議性的,並且在你執行寫入操做時可能會發生變化。若是發生錯誤,寫入數據到阻塞描述符,也會使事件處理器中止在執行中途,並阻止dispatch queue執行其它任務。串行queue會產生死鎖,併發queue則會減小可以執行的任務數量。

下面是使用dispatch source寫入數據到文件的例子,建立文件後,函數傳遞文件描述符到事件處理器。MyGetData函數負責提供要寫入的數據,在數據寫入到文件以後,事件處理器取消dispatch source,阻止再次調用。此時dispatch source的擁有者需負責釋放dispatch source。

 
  1. dispatch_source_t WriteDataToFile(const char* filename) 
  2.     int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 
  3.                       (S_IRUSR | S_IWUSR | S_ISUID | S_ISGID)); 
  4.     if (fd == -1) 
  5.         return NULL; 
  6.     fcntl(fd, F_SETFL); // Block during the write. 
  7.   
  8.     dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 
  9.     dispatch_source_t writeSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_WRITE, 
  10.                             fd, 0, queue); 
  11.     if (!writeSource) 
  12.     { 
  13.         close(fd); 
  14.         return NULL; 
  15.     } 
  16.   
  17.     dispatch_source_set_event_handler(writeSource, ^{ 
  18.         size_t bufferSize = MyGetDataSize(); 
  19.         void* buffer = malloc(bufferSize); 
  20.   
  21.         size_t actual = MyGetData(buffer, bufferSize); 
  22.         write(fd, buffer, actual); 
  23.   
  24.         free(buffer); 
  25.   
  26.         // Cancel and release the dispatch source when done. 
  27.         dispatch_source_cancel(writeSource); 
  28.     }); 
  29.   
  30.     dispatch_source_set_cancel_handler(writeSource, ^{close(fd);}); 
  31.     dispatch_resume(writeSource); 
  32.     return (writeSource); 

監控文件系統對象

若是須要監控文件系統對象的變化,能夠設置一個 DISPATCH_SOURCE_TYPE_VNODE 類型的dispatch source,你能夠從這個dispatch source中接收文件刪除、寫入、重命名等通知。你還能夠獲得文件的特定元數據信息變化通知。

在dispatch source正在處理事件時,dispatch source中指定的文件描述符必須保持打開狀態。

下面例子監控一個文件的文件名變化,並在文件名變化時執行一些操做(自定義的 MyUpdateFileName 函數)。因爲文件描述符專門爲dispatch source打開,dispatch source安裝了取消處理器來關閉文件描述符。這個例子中的文件描述符關聯到底層的文件系統對象,所以同一個dispatch source能夠用來檢測屢次文件名變化。

 
  1. dispatch_source_t MonitorNameChangesToFile(const char* filename) 
  2.    int fd = open(filename, O_EVTONLY); 
  3.    if (fd == -1) 
  4.       return NULL; 
  5.   
  6.    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 
  7.    dispatch_source_t source = dispatch_source_create(DISPATCH_SOURCE_TYPE_VNODE, 
  8.                 fd, DISPATCH_VNODE_RENAME, queue); 
  9.    if (source) 
  10.    { 
  11.       // Copy the filename for later use. 
  12.       int length = strlen(filename); 
  13.       char* newString = (char*)malloc(length + 1); 
  14.       newString = strcpy(newString, filename); 
  15.       dispatch_set_context(source, newString); 
  16.   
  17.       // Install the event handler to process the name change 
  18.       dispatch_source_set_event_handler(source, ^{ 
  19.             const char*  oldFilename = (char*)dispatch_get_context(source); 
  20.             MyUpdateFileName(oldFilename, fd); 
  21.       }); 
  22.   
  23.       // Install a cancellation handler to free the descriptor 
  24.       // and the stored string. 
  25.       dispatch_source_set_cancel_handler(source, ^{ 
  26.           char* fileStr = (char*)dispatch_get_context(source); 
  27.           free(fileStr); 
  28.           close(fd); 
  29.       }); 
  30.   
  31.       // Start processing events. 
  32.       dispatch_resume(source); 
  33.    } 
  34.    else 
  35.       close(fd); 
  36.   
  37.    return source; 

監測信號

應用能夠接收許多不一樣類型的信號,如不可恢復的錯誤(非法指令)、或重要信息的通知(如子進程退出)。傳統編程中,應用使用 sigaction 函數安裝信號處理器函數,信號到達時同步處理信號。若是你只是想信號到達時獲得通知,並不想實際地處理該信號,可使用信號dispatch source來異步處理信號。

信號dispatch source不能替代 sigaction 函數提供的同步信號處理機制。同步信號處理器能夠捕獲一個信號,並阻止它停止應用。而信號dispatch source只容許你監測信號的到達。此外,你不能使用信號dispatch source獲取全部類型的信號,如SIGILL, SIGBUS, SIGSEGV信號。

因爲信號dispatch source在dispatch queue中異步執行,它沒有同步信號處理器的一些限制。例如信號dispatch source的事件處理器能夠調用任何函數。靈活性增大的代價是,信號到達和dispatch source事件處理器被調用的延遲可能會增大。

下面例子配置信號dispatch source來處理SIGHUP信號,事件處理器調用 MyProcessSIGHUP 函數,用來處理信號。

 
  1. void InstallSignalHandler() 
  2.    // Make sure the signal does not terminate the application. 
  3.    signal(SIGHUP, SIG_IGN); 
  4.   
  5.    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 
  6.    dispatch_source_t source = dispatch_source_create(DISPATCH_SOURCE_TYPE_SIGNAL, SIGHUP, 0, queue); 
  7.   
  8.    if (source) 
  9.    { 
  10.       dispatch_source_set_event_handler(source, ^{ 
  11.          MyProcessSIGHUP(); 
  12.       }); 
  13.   
  14.       // Start processing signals 
  15.       dispatch_resume(source); 
  16.    } 

監控進程

進程dispatch source能夠監控特定進程的行爲,並適當地響應。父進程可使用dispatch source來監控本身建立的全部子進程,例如監控子進程的死亡;相似地,子進程也可使用dispatch source來監控父進程,例如在父進程退出時本身也退出。

下面例子安裝了一個進程dispatch source,監控父進程的終止。當父進程退出時,dispatch source設置一些內部狀態信息,告知子進程本身應該退出。MySetAppExitFlag 函數應該設置一個適當的標誌,容許子進程終止。因爲dispatch source自主運行,所以本身擁有本身,在程序關閉時會取消並釋放本身。

 
  1. void MonitorParentProcess() 
  2.    pid_t parentPID = getppid(); 
  3.   
  4.    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 
  5.    dispatch_source_t source = dispatch_source_create(DISPATCH_SOURCE_TYPE_PROC, 
  6.                                                       parentPID, DISPATCH_PROC_EXIT, queue); 
  7.    if (source) 
  8.    { 
  9.       dispatch_source_set_event_handler(source, ^{ 
  10.          MySetAppExitFlag(); 
  11.          dispatch_source_cancel(source); 
  12.          dispatch_release(source); 
  13.       }); 
  14.       dispatch_resume(source); 
  15.    } 

取消一個Dispatch Source

除非你顯式地調用 dispatch_source_cancel 函數,dispatch source將一直保持活動,取消一個dispatch source會中止遞送新事件,而且不能撤銷。所以你一般在取消dispatch source後當即釋放它:

 
  1. void RemoveDispatchSource(dispatch_source_t mySource) 
  2.    dispatch_source_cancel(mySource); 
  3.    dispatch_release(mySource); 

取消一個dispatch source是異步操做,調用 dispatch_source_cancel 以後,不會再有新的事件被處理,可是正在被dispatch source處理的事件會繼續被處理完成。在處理完最後的事件以後,dispatch source會執行本身的取消處理器。

取消處理器是你最後的執行機會,在那裏執行內存或資源的釋放工做。例如描述符或mach port類型的dispatch source,必須提供取消處理器,用來關閉描述符或mach port

掛起和繼續Dispatch Source

你可使用 dispatch_suspend 和 dispatch_resume 臨時地掛起和繼續dispatch source的事件遞送。這兩個函數分別增長和減小dispatch 對象的掛起計數。所以,你必須每次 dispatch_suspend 調用以後,都須要相應的 dispatch_resume 才能繼續事件遞送。

掛起一個dispatch source期間,發生的任何事件都會被累積,直到dispatch source繼續。可是不會遞送全部事件,而是先合併到單一事件,而後再一次遞送。例如你監控一個文件的文件名變化,就只會遞送最後一次的變化事件。

相關文章
相關標籤/搜索