iOS POSIX多線程編程

關(guān)于多線程的介紹、多線程的創(chuàng)建使用場景Runloop可以參考《iOS多線程編程指南》。已上傳到GitHub倉庫。

這里主要說明線程同步技術(shù)的鎖,尤其是POSIX互斥鎖。已經(jīng)寫成了Demo,可以對照著看。GitHub地址:https://github.com/xiaoL0204/PthreadsDemo
將來也會從項目中提取更多Demo出來,對應(yīng)不同的多線程知識。

這個Demo適用如下場景:同時向服務(wù)器取不同的數(shù)據(jù),每次回調(diào)以后在子線程中處理數(shù)據(jù)(要共享數(shù)據(jù)),在主線程中顯示數(shù)據(jù)。
因為數(shù)據(jù)的處理是在子線程中,在主線程UITableView reloadData顯示數(shù)據(jù);必須等到tableView刷新完成以后才能處理下一次數(shù)據(jù)回調(diào),否則在reload data時數(shù)據(jù)源修改了會引起崩潰。

對于這樣的場景,這里考慮使用條件變量進行線程間同步。
原理如下:在數(shù)據(jù)處理子線程中等待條件成立,若不成立則會一直等待,直到主線程刷新完成并發(fā)出激活信號后重新激活數(shù)據(jù)處理子線程;若成立則不會等待,直接進入主線程刷新UI。

Demo 使用了如下變量和函數(shù):

1、pthread_mutex_t
2、pthread_cond_t
3、pthread_cond_wait()
4、pthread_cond_signal()
5、pthread_join()
它們的含義和使用方法如下:

1、pthread_mutex_t 互斥鎖

兩種方法創(chuàng)建互斥鎖,靜態(tài)方式動態(tài)方式

靜態(tài)方式:

使用宏PTHREAD_MUTEX_INITIALIZER來初始化互斥鎖,屬性參數(shù)默認:

pthread_mutex_t mutex_t = PTHREAD_MUTEX_INITIALIZER;

動態(tài)方式:

可以指定互斥鎖屬性:

int pthread_mutex_init(pthread_mutex_t * __restrict,
        const pthread_mutexattr_t * _Nullable __restrict);

2、pthread_cond_t 條件變量

運用于線程間同步。一般和pthread_mutex_t一起使用。
可以使用靜態(tài)方式動態(tài)方式初始化條件變量

靜態(tài)方式:

用宏PTHREAD_COND_INITIALIZER來初始化靜態(tài)定義的條件變量,使其具有缺省屬性

動態(tài)方式:

指定條件變量的屬性:

int pthread_cond_init(
        pthread_cond_t * __restrict,
        const pthread_condattr_t * _Nullable __restrict)
        __DARWIN_ALIAS(pthread_cond_init);

3、pthread_cond_wait()函數(shù)

int pthread_cond_wait(pthread_cond_t * __restrict,
        pthread_mutex_t * __restrict) __DARWIN_ALIAS_C(pthread_cond_wait);

pthread_cond_wait() 必須與pthread_mutex_t 配套使用。
用于阻塞當(dāng)前線程,等待別的線程使用 pthread_cond_signal()pthread_cond_broadcast()來喚醒它。
具體來說,就是函數(shù)將解鎖pthread_mutex_t指向的互斥鎖,并使當(dāng)前線程阻塞在pthread_mutex_t指向的條件變量上。
因此,在使用時,最好的方法是循環(huán)調(diào)用pthread_cond_wait函數(shù),循環(huán)的終止條件為額外定義的變量。如下面核心代碼中的while循環(huán)。

4、pthread_cond_signal()函數(shù)

int pthread_cond_signal(pthread_cond_t *);

作用:激活一個處于阻塞等待狀態(tài)的線程,存在多個阻塞線程時按規(guī)則激活其中第一個。

pthread_cond_signal 函數(shù)會發(fā)送信號給其它阻塞在pthread_cond_t指向的條件變量的線程,阻塞在該條件變量上的線程接收信號后,脫離阻塞狀態(tài),繼續(xù)執(zhí)行后續(xù)代碼。
使用pthread_cond_signal一般不會有“驚群現(xiàn)象”產(chǎn)生,他最多只給一個線程發(fā)信號。假如有多個線程阻塞在這個條件變量的話,會根據(jù)各阻塞線程優(yōu)先級的高低確定哪個接收到信號的線程接繼續(xù)執(zhí)行后續(xù)代碼。如果各線程優(yōu)先級相同,則按入隊順序激活其中第一個。pthread_cond_signal()只會激活最多一個等待該條件的線程。
pthread_cond_signal 在多處理器上可能同時喚醒多個線程,當(dāng)你只能讓一個線程處理某個任務(wù)時,其它被喚醒的線程就需要繼續(xù) wait。所以pthread_cond_wait()需要使用while作為外部判斷。

5、pthread_join()函數(shù)

int pthread_join(pthread_t , void * _Nullable * _Nullable)
        __DARWIN_ALIAS_C(pthread_join);

使一個線程等待另一個線程結(jié)束。

其它函數(shù):

6、pthread_cond_timedwait()函數(shù)

int pthread_cond_timedwait(
        pthread_cond_t * __restrict, pthread_mutex_t * __restrict,
        const struct timespec * _Nullable __restrict)
        __DARWIN_ALIAS_C(pthread_cond_timedwait);

函數(shù)到了一定的時間,即使條件未發(fā)生也會解除阻塞。這個時間由參數(shù)abstime指定。

7、pthread_cond_broadcast()函數(shù)

int pthread_cond_broadcast(pthread_cond_t *);

喚醒所有被pthread_cond_wait()函數(shù)阻塞在某個條件變量上的線程,pthread_cond_t指針指向這個條件變量。


主要的方法實現(xiàn):

- (void)fetchHomeData{
    self.themeListArr = [NSMutableArray array];
    __weak __block typeof(self) weakSelf = self;
    
    NSMutableArray *serverThemeArr = [NSMutableArray array];
    dispatch_queue_t queue_t = dispatch_queue_create("com.dispatch.themeserial", DISPATCH_QUEUE_SERIAL);
    __block BOOL oneJobdone = YES;
    __block pthread_cond_t cond_t = PTHREAD_COND_INITIALIZER;
    //為了防止競爭,條件變量的使用總是和一個互斥鎖結(jié)合在一起。
    __block pthread_mutex_t mutex_t = PTHREAD_MUTEX_INITIALIZER;
    
    [[XLDataFetchHandler sharedInstance] requestAllHomeThemeListWithCompletion:^(NSString *themeIds,NSArray *themeList, BOOL httpDone) {
        dispatch_async(queue_t, ^{
            pthread_t threadId = pthread_self();
            
            NSLog(@"requestAllHomeThemeListWithCompletion   fetch data!  themeIds:%@",themeIds);
            
            while (!oneJobdone) {  //為何使用while判斷:防止可能存在的“驚群效應(yīng)”。pthread_cond_wait里的線程可能會被意外喚醒,如果這個時候oneJobdone為NO,則說明UI沒有刷新完成。這個時候,應(yīng)該讓線程繼續(xù)進入pthread_cond_wait
                pthread_cond_wait(&cond_t, &mutex_t);   // pthread_cond_wait用于阻塞當(dāng)前線程,等待別的線程使用 pthread_cond_signal() 或pthread_cond_broadcast來喚醒它
            }
            
            oneJobdone = NO;
            
            [serverThemeArr addObjectsFromArray:themeList];
            if (httpDone) {
                self.themeListArr = [NSMutableArray arrayWithArray:serverThemeArr];
//                [self sortThemeListArray];   //請求結(jié)束,排序
            }else{
//                [weakSelf filterOriginThemeListWithPartList:themeList];   //一次請求結(jié)束,過濾
            }
            
            
            dispatch_async(dispatch_get_main_queue(), ^{
                NSLog(@"requestAllHomeThemeListWithCompletion   reloadData before");
//table view reload,不知道什么時候結(jié)束。所以要在reload data完成后發(fā)信號
                [weakSelf.tableView reloadData];
                NSLog(@"requestAllHomeThemeListWithCompletion   reloadData after");
                oneJobdone = YES;
                //對條件變量cond_t發(fā)信號,激活一個等待該條件的線程,存在多個等待線程時按入隊順序激活其中一個
                pthread_cond_signal(&cond_t);
                NSLog(@"requestAllHomeThemeListWithCompletion   signal");
            });
            pthread_join(threadId, NULL);
        });
        
    }];
    
}

運行效果圖:

效果圖1、順序執(zhí)行
效果圖2、阻塞執(zhí)行
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 轉(zhuǎn)自:Youtherhttps://www.cnblogs.com/youtherhome/archive/201...
    njukay閱讀 1,721評論 0 52
  • 簡介 線程創(chuàng)建 線程屬性設(shè)置 線程參數(shù)傳遞 線程優(yōu)先級 線程的數(shù)據(jù)處理 線程的分離狀態(tài) 互斥鎖 信號量 一 線程創(chuàng)...
    第八區(qū)閱讀 8,713評論 1 6
  • 引用自多線程編程指南應(yīng)用程序里面多個線程的存在引發(fā)了多個執(zhí)行線程安全訪問資源的潛在問題。兩個線程同時修改同一資源有...
    Mitchell閱讀 2,123評論 1 7
  • 摘要 線程概念,線程與進程的區(qū)別與聯(lián)系學(xué)會線程控制,線程創(chuàng)建,線程終止,線程等待了解線程分離與線程安全學(xué)會線程同步...
    狼之足跡閱讀 529評論 2 3
  • iOS 多線程系列 -- 基礎(chǔ)概述iOS 多線程系列 -- pthreadiOS 多線程系列 -- NSThrea...
    shannoon閱讀 2,793評論 1 8

友情鏈接更多精彩內(nèi)容