日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

GCD简介四:挂起,目标指定,信号量

發布時間:2024/7/23 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 GCD简介四:挂起,目标指定,信号量 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
一、Dispatch Queue掛起
dispatch queue可以被掛起和恢復。使用 dispatch_suspend函數來掛起,使用 ?dispatch_resume 函數來恢復。這兩個函數的行為是如你所愿的。另外,這兩個還是也可以用于dispatch source。
一個要注意的地方是,dispatch queue的掛起是block粒度的。換句話說,掛起一個queue并不會將當前正在執行的block掛起。它會允許當前執行的block執行完畢,然后后續的block不再會被執行,直至queue被恢復。
還有一個注意點:從man頁上得來的:如果你掛起了一個queue或者source,那么銷毀它之前,必須先對其進行恢復。
二、Dispatch Queue目標指定
所有的用戶隊列都有一個目標隊列概念。從本質上講,一個用戶隊列實際上是不執行任何任務的,但是它會將任務傳遞給它的目標隊列來執行。通常,目標隊列是默認優先級的全局隊列。
用戶隊列的目標隊列可以用函數 dispatch_set_target_queue來修改。我們可以將任意dispatch queue傳遞給這個函數,甚至可以是另一個用戶隊列,只要別構成循環就行。這個函數可以用來設定用戶隊列的優先級。比如我們可以將用戶隊列的目標隊列設定為低優先級的全局隊列,那么我們的用戶隊列中的任務都會以低優先級執行。高優先級也是一樣道理。
有一個用途,是將用戶隊列的目標定為main queue。這會導致所有提交到該用戶隊列的block在主線程中執行。這樣做來替代直接在主線程中執行代碼的好處在于,我們的用戶隊列可以單獨地被掛起和恢復,還可以被重定目標至一個全局隊列,然后所有的block會變成在全局隊列上執行(只要你確保你的代碼離開主線程不會有問題)。
還有一個用途,是將一個用戶隊列的目標隊列指定為另一個用戶隊列。這樣做可以強制多個隊列相互協調地串行執行,這樣足以構建一組隊列,通過掛起和暫停那個目標隊列,我們可以掛起和暫停整個組。想象這樣一個程序:它掃描一組目錄并且加載目錄中的內容。為了避免磁盤競爭,我們要確定在同一個物理磁盤上同時只有一個文件加載任務在執行。而希望可以同時從不同的物理磁盤上讀取多個文件。要實現這個,我們要做的就是創建一個dispatch queue結構,該結構為磁盤結構的鏡像。
首先,我們會掃描系統并找到各個磁盤,為每個磁盤創建一個用戶隊列。然后掃描文件系統,并為每個文件系統創建一個用戶隊列,將這些用戶隊列的目標隊列指向合適的磁盤用戶隊列。最后,每個目錄掃描器有自己的隊列,其目標隊列指向目錄所在的文件系統的隊列。目錄掃描器枚舉自己的目錄并為每個文件向自己的隊列提交一個block。由于整個系統的建立方式,就使得每個物理磁盤被串行訪問,而多個物理磁盤被并行訪問。除了隊列初始化過程,我們根本不需要手動干預什么東西。
三、信號量 dispatch的信號量是像其他的信號量一樣的,如果你熟悉其他多線程系統中的信號量,那么這一節的東西再好理解不過了。
信號量是一個整形值并且具有一個初始計數值,并且支持兩個操作:信號通知和等待。當一個信號量被信號通知,其計數會被增加。當一個線程在一個信號量上等待時,線程會被阻塞(如果有必要的話),直至計數器大于零,然后線程會減少這個計數。
我們使用函數 ?dispatch_semaphore_create 來創建dispatch信號量,使用函數 ?dispatch_semaphore_signal 來信號通知,使用函數 dispatch_semaphore_wait 來等待。這些函數的man頁有兩個很好的例子,展示了怎樣使用信號量來同步任務和有限資源訪問控制。 單次初始化
GCD還提供單詞初始化支持,這個與pthread中的函數 ?pthread_once 很相似。GCD提供的方式的優點在于它使用block而非函數指針,這就允許更自然的代碼方式: 這個特性的主要用途是惰性單例初始化或者其他的線程安全數據共享。典型的單例初始化技術看起來像這樣(線程安全的): ? ? + (id)sharedWhatever ? ? { ? ? ? ? static Whatever *whatever = nil; ? ? ? ? @synchronized([Whatever class]) ? ? ? ? { ? ? ? ? ? ? if(!whatever) ? ? ? ? ? ? ? ? whatever = [[Whatever alloc] init]; ? ? ? ? } ? ? ? ? return whatever; ? ? } 這挺好的,但是代價比較昂貴;每次調用 ?+sharedWhatever 函數都會付出取鎖的代價,即使這個鎖只需要進行一次。確實有更風騷的方式來實現這個,使用類似雙向鎖或者是原子操作的東西,但是這樣挺難弄而且容易出錯。
使用GCD,我們可以這樣重寫上面的方法,使用函數 dispatch_once: ? ? + (id)sharedWhatever ? ? { ? ? ? ? static dispatch_once_t pred; ? ? ? ? static Whatever *whatever = nil; ? ? ? ? dispatch_once(&pred, ^{ ? ? ? ? ? ? whatever = [[Whatever alloc] init]; ? ? ? ? }); ? ? ? ? return whatever; ? ? }
這個稍微比 @synchronized方法簡單些,并且GCD確保以更快的方式完成這些檢測,它保證block中的代碼在任何線程通過 ?dispatch_once 調用之前被執行,但它不會強制每次調用這個函數都讓代碼進行同步控制。實際上,如果你去看這個函數所在的頭文件,你會發現目前它的實現其實是一個宏,進行了內聯的初始化測試,這意味著通常情況下,你不用付出函數調用的負載代價,并且會有更少的同步控制負載。
轉載自:http://www.dreamingwish.com/dream-2012/gcd-four-the-the-odds-and-ends.html

總結

以上是生活随笔為你收集整理的GCD简介四:挂起,目标指定,信号量的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。