IOS開發-多線程開發之安全執行緒篇

來源:互聯網
上載者:User

IOS開發-多線程開發之安全執行緒篇
前言:一塊資源可能會被多個線程共用,也就是多個線程可能會訪問同一塊資源,比如多個線程訪問同一個對象、同一個變數、同一個檔案和同一個方法等。因此當多個線程訪問同一塊資源時,很容易會發生資料錯誤及資料不安全等問題。因此要避免這些問題,我們需要使用“線程鎖”來實現。   本文主要論述IOS建立鎖的方法(總結): 一、使用關鍵字 1)@synchronized(互斥鎖) 優點:使用@synchronized關鍵字可以很方便地建立鎖對象,而且不用顯式的建立鎖對象。 缺點:會隱式添加一個異常處理來保護代碼,該異常處理會在異常拋出的時候自動釋放互斥鎖。而這種隱式的異常處理會帶來系統的額外開銷,為最佳化資源,你可以使用鎖對象。 二、“Object-C”語言 1)NSLock(互斥鎖) 2)NSRecursiveLock(遞迴鎖) 條件鎖,遞迴或迴圈方法時使用此方法實現鎖,可避免死結等問題。 3)NSConditionLock(條件鎖) 使用此方法可以指定,只有滿足條件的時候才可以解鎖。 4)NSDistributedLock(分布式鎖) 在IOS中不需要用到,也沒有這個方法,因此本文不作介紹,這裡寫出來只是想讓大家知道有這個鎖存在。 如果想要學習NSDistributedLock的話,你可以建立MAC OS的項目自己演練,方法請自行Google,謝謝。 三、C語言 1)pthread_mutex_t(互斥鎖) 2)GCD-訊號量(“互斥鎖”) 3)pthread_cond_t(條件鎖)   安全執行緒 —— 鎖 一、使用關鍵字: 1)@synchronized  // 執行個體類personPerson *person = [[Person alloc] init]; // 線程Adispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{    @synchronized(person) {        [person personA];        [NSThread sleepForTimeInterval:3]; // 線程休眠3秒    }}); // 線程Bdispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{    @synchronized(person) {        [person personB];    }}); 關鍵字@synchronized的使用,鎖定的對象為鎖的唯一標識,只有標識相同時,才滿足互斥。如果線程B鎖對象person改為self或其它標識,那麼線程B將不會被阻塞。你是否看到@synchronized(self) ,也是對的。它可以鎖任何對象,描述為@synchronized(anObj)。   二、Object-C語言 1)使用NSLock實現鎖  // 執行個體類personPerson *person = [[Person alloc] init];// 建立鎖NSLock *myLock = [[NSLock alloc] init]; // 線程Adispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{    [myLock lock];    [person personA];    [NSThread sleepForTimeInterval:5];    [myLock unlock];}); // 線程Bdispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{    [myLock lock];    [person personB];    [myLock unlock];});  程式運行結果:線程B會等待線程A解鎖後,才會去執行線程B。如果線程B把lock和unlock方法去掉之後,則線程B不會被阻塞,這個和synchronized的一樣,需要使用同樣的鎖對象才會互斥。 NSLock類還提供tryLock方法,意思是嘗試鎖定,當鎖定失敗時,不會阻塞進程,而是會返回NO。你也可以使用lockBeforeDate:方法,意思是在指定時間之前嘗試鎖定,如果在指定時間前都不能鎖定,也是會返回NO。 注意:鎖定(lock)和解鎖(unLock)必須配對使用   2)使用NSRecursiveLock類實現鎖   // 執行個體類personPerson *person = [[Person alloc] init];// 建立鎖對象NSRecursiveLock *theLock = [[NSRecursiveLock alloc] init]; // 建立遞迴方法static void (^testCode)(int);testCode = ^(int value) {    [theLock tryLock];    if (value > 0)    {        [person personA];        [NSThread sleepForTimeInterval:1];        testCode(value - 1);    }    [theLock unlock];}; //線程Adispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{    testCode(5);}); //線程Bdispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{    [theLock lock];    [person personB];    [theLock unlock];}); 如果我們把NSRecursiveLock類換成NSLock類,那麼程式就會死結。因為在此例子中,遞迴方法會造成鎖被多次鎖定(Lock),所以自己也被阻塞了。而使用NSRecursiveLock類,則可以避免這個問題。   3)使用NSConditionLock(條件鎖)類實現鎖: 使用此方法可以建立一個指定開鎖的條件,只有滿足條件,才能開鎖。  // 執行個體類personPerson *person = [[Person alloc] init];// 建立條件鎖NSConditionLock *conditionLock = [[NSConditionLock alloc] init]; // 線程Adispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{    [conditionLock lock];    [person personA];    [NSThread sleepForTimeInterval:5];    [conditionLock unlockWithCondition:10];}); // 線程Bdispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{    [conditionLock lockWhenCondition:10];    [person personB];    [conditionLock unlock];}); 線程A使用的是lock方法,因此會直接進行鎖定,並且指定了只有滿足10的情況下,才能成功解鎖。 unlockWithCondition:方法,建立條件鎖,參數傳入“整型”。lockWhenCondition:方法,則為解鎖,也是傳入一個“整型”的參數。   三、C語言 1)使用pthread_mutex_t實現鎖 注意:必須在標頭檔匯入:#import <pthread.h>  // 執行個體類personPerson *person = [[Person alloc] init]; // 建立鎖對象__block pthread_mutex_t mutex;pthread_mutex_init(&mutex, NULL); // 線程Adispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{    pthread_mutex_lock(&mutex);    [person personA];    [NSThread sleepForTimeInterval:5];    pthread_mutex_unlock(&mutex);}); // 線程Bdispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{    pthread_mutex_lock(&mutex);    [person personB];    pthread_mutex_unlock(&mutex);}); 實現效果和上例的相一致    2)使用GCD實現“鎖”(訊號量) GCD提供一種訊號的機制,使用它我們可以建立“鎖”(訊號量和鎖是有區別的,具體請自行百度)。  // 執行個體類personPerson *person = [[Person alloc] init]; // 建立並設定信量dispatch_semaphore_t semaphore = dispatch_semaphore_create(1); // 線程Adispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);    [person personA];    [NSThread sleepForTimeInterval:5];    dispatch_semaphore_signal(semaphore);}); // 線程Bdispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);    [person personB];    dispatch_semaphore_signal(semaphore);}); 效果也是和上例介紹的相一致。 我在這裡解釋一下代碼。dispatch_semaphore_wait方法是把訊號量加1,dispatch_semaphore_signal是把訊號量減1。 我們把訊號量當作是一個計數器,當計數器是一個非負整數時,所有通過它的線程都應該把這個整數減1。如果計數器大於0,那麼則允許訪問,並把計數器減1。如果為0,則訪問被禁止,所有通過它的線程都處於等待的狀態。   3)使用POSIX(條件鎖)建立鎖  // 執行個體類personPerson *person = [[Person alloc] init]; // 建立互斥鎖__block pthread_mutex_t mutex;pthread_mutex_init(&mutex, NULL);// 建立條件鎖__block pthread_cond_t cond;pthread_cond_init(&cond, NULL); // 線程Adispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{    pthread_mutex_lock(&mutex);    pthread_cond_wait(&cond, &mutex);    [person personA];    pthread_mutex_unlock(&mutex);}); // 線程Bdispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{    pthread_mutex_lock(&mutex);    [person personB];    [NSThread sleepForTimeInterval:5];    pthread_cond_signal(&cond);    pthread_mutex_unlock(&mutex);}); 效果:程式會首先調用線程B,在5秒後再調用線程A。因為線上程A中建立了等待條件鎖,線程B有啟用鎖,只有當線程B執行完後會啟用線程A。 pthread_cond_wait方法為等待條件鎖。 pthread_cond_signal方法為激動一個相同條件的條件鎖。     簡單總結: 一般來說,如果項目不大,我們都會偷點懶,直接使用關鍵字@synchronized建立鎖,懶人方法。其次可以使用蘋果提供的OC方法,最後才會去使用C去建立鎖。  

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.