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

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

iOS多线程:『pthread、NSThread』详尽总结

發(fā)布時(shí)間:2025/3/17 编程问答 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 iOS多线程:『pthread、NSThread』详尽总结 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

2019獨(dú)角獸企業(yè)重金招聘Python工程師標(biāo)準(zhǔn)>>>

本文用來(lái)介紹 iOS 多線程中,pthread、NSThread?的使用方法及實(shí)現(xiàn)。
第一部分:pthread 的使用、其他相關(guān)方法。
第二部分:NSThread 的使用、線程相關(guān)用法、線程狀態(tài)控制方法、線程之間的通信、線程安全和線程同步,以及線程的狀態(tài)轉(zhuǎn)換相關(guān)知識(shí)。

文中 Demo 我已放在了 Github 上,Demo 鏈接:傳送門(mén)

1. pthread

1.1 pthread 簡(jiǎn)介

pthread 是一套通用的多線程的 API,可以在Unix / Linux / Windows 等系統(tǒng)跨平臺(tái)使用,使用 C 語(yǔ)言編寫(xiě),需要程序員自己管理線程的生命周期,使用難度較大,我們?cè)?iOS 開(kāi)發(fā)中幾乎不使用 pthread,但是還是來(lái)可以了解一下的。

引自?百度百科
POSIX 線程(POSIX threads),簡(jiǎn)稱(chēng) Pthreads,是線程的 POSIX 標(biāo)準(zhǔn)。該標(biāo)準(zhǔn)定義了創(chuàng)建和操縱線程的一整套 API。在類(lèi)Unix操作系統(tǒng)(Unix、Linux、Mac OS X等)中,都使用 Pthreads 作為操作系統(tǒng)的線程。Windows 操作系統(tǒng)也有其移植版 pthreads-win32。

引自?維基百科
POSIX 線程(英語(yǔ):POSIX Threads,常被縮寫(xiě) 為 Pthreads)是 POSIX 的線程標(biāo)準(zhǔn),定義了創(chuàng)建和操縱線程的一套 API。
實(shí)現(xiàn) POSIX 線程標(biāo)準(zhǔn)的庫(kù)常被稱(chēng)作 Pthreads,一般用于 Unix-like POSIX 系統(tǒng),如 Linux、Solaris。但是 Microsoft Windows 上的實(shí)現(xiàn)也存在,例如直接使用 Windows API 實(shí)現(xiàn)的第三方庫(kù) pthreads-w32;而利用 Windows 的 SFU/SUA 子系統(tǒng),則可以使用微軟提供的一部分原生 POSIX API。

1.2 pthread 使用方法

  • 首先要包含頭文件#import <pthread.h>
  • 其次要?jiǎng)?chuàng)建線程,并開(kāi)啟線程執(zhí)行任務(wù)
  • 1 2 3 4 5 6 7 8 9 10 11 12 13 // 1. 創(chuàng)建線程: 定義一個(gè)pthread_t類(lèi)型變量 pthread_t thread; // 2. 開(kāi)啟線程: 執(zhí)行任務(wù) pthread_create(&thread, NULL, run, NULL); // 3. 設(shè)置子線程的狀態(tài)設(shè)置為 detached,該線程運(yùn)行結(jié)束后會(huì)自動(dòng)釋放所有資源 pthread_detach(thread);void * run(void *param) // 新線程調(diào)用方法,里邊為需要執(zhí)行的任務(wù) { NSLog(@"%@", [NSThread currentThread]);return NULL; }
    • pthread_create(&thread, NULL, run, NULL);?中各項(xiàng)參數(shù)含義:
    • 第一個(gè)參數(shù)&thread是線程對(duì)象,指向線程標(biāo)識(shí)符的指針
    • 第二個(gè)是線程屬性,可賦值NULL
    • 第三個(gè)run表示指向函數(shù)的指針(run對(duì)應(yīng)函數(shù)里是需要在新線程中執(zhí)行的任務(wù))
    • 第四個(gè)是運(yùn)行函數(shù)的參數(shù),可賦值NULL

    1.3 pthread 其他相關(guān)方法

    • pthread_create()?創(chuàng)建一個(gè)線程
    • pthread_exit()?終止當(dāng)前線程
    • pthread_cancel()?中斷另外一個(gè)線程的運(yùn)行
    • pthread_join()?阻塞當(dāng)前的線程,直到另外一個(gè)線程運(yùn)行結(jié)束
    • pthread_attr_init()?初始化線程的屬性
    • pthread_attr_setdetachstate()?設(shè)置脫離狀態(tài)的屬性(決定這個(gè)線程在終止時(shí)是否可以被結(jié)合)
    • pthread_attr_getdetachstate()?獲取脫離狀態(tài)的屬性
    • pthread_attr_destroy()?刪除線程的屬性
    • pthread_kill()?向線程發(fā)送一個(gè)信號(hào)

    2. NSThread

    NSThread 是蘋(píng)果官方提供的,使用起來(lái)比 pthread 更加面向?qū)ο?#xff0c;簡(jiǎn)單易用,可以直接操作線程對(duì)象。不過(guò)也需要需要程序員自己管理線程的生命周期(主要是創(chuàng)建),我們?cè)陂_(kāi)發(fā)的過(guò)程中偶爾使用 NSThread。比如我們會(huì)經(jīng)常調(diào)用[NSThread currentThread]來(lái)顯示當(dāng)前的進(jìn)程信息。

    下邊我們說(shuō)說(shuō) NSThread 如何使用。

    2.1 創(chuàng)建、啟動(dòng)線程

    • 先創(chuàng)建線程,再啟動(dòng)線程
    1 2 3 4 5 6 7 8 9 // 1. 創(chuàng)建線程 NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil]; // 2. 啟動(dòng)線程 [thread start]; // 線程一啟動(dòng),就會(huì)在線程thread中執(zhí)行self的run方法// 新線程調(diào)用方法,里邊為需要執(zhí)行的任務(wù) - (void)run { NSLog(@"%@", [NSThread currentThread]); }
    • 創(chuàng)建線程后自動(dòng)啟動(dòng)線程
    1 2 3 4 5 6 7 // 1. 創(chuàng)建線程后自動(dòng)啟動(dòng)線程 [NSThread detachNewThreadSelector:@selector(run) toTarget:self withObject:nil];// 新線程調(diào)用方法,里邊為需要執(zhí)行的任務(wù) - (void)run { NSLog(@"%@", [NSThread currentThread]); }
    • 隱式創(chuàng)建并啟動(dòng)線程
    1 2 3 4 5 6 7 // 1. 隱式創(chuàng)建并啟動(dòng)線程 [self performSelectorInBackground:@selector(run) withObject:nil];// 新線程調(diào)用方法,里邊為需要執(zhí)行的任務(wù) - (void)run { NSLog(@"%@", [NSThread currentThread]); }

    2.2 線程相關(guān)用法

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 // 獲得主線程 + (NSThread *)mainThread;// 判斷是否為主線程(對(duì)象方法) - (BOOL)isMainThread;// 判斷是否為主線程(類(lèi)方法) + (BOOL)isMainThread;// 獲得當(dāng)前線程 NSThread *current = [NSThread currentThread];// 線程的名字——setter方法 - (void)setName:(NSString *)n;// 線程的名字——getter方法 - (NSString *)name;

    2.3 線程狀態(tài)控制方法

    • 啟動(dòng)線程方法
    1 2 - (void)start; // 線程進(jìn)入就緒狀態(tài) -> 運(yùn)行狀態(tài)。當(dāng)線程任務(wù)執(zhí)行完畢,自動(dòng)進(jìn)入死亡狀態(tài)
    • 阻塞(暫停)線!程方法
    1 2 3 + (void)sleepUntilDate:(NSDate *)date; + (void)sleepForTimeInterval:(NSTimeInterval)ti; // 線程進(jìn)入阻塞狀態(tài)
    • 強(qiáng)制停止線程
    1 2 + (void)exit; // 線程進(jìn)入死亡狀態(tài)

    2.4 線程之間的通信

    在開(kāi)發(fā)中,我們經(jīng)常會(huì)在子線程進(jìn)行耗時(shí)操作,操作結(jié)束后再回到主線程去刷新 UI。這就涉及到了子線程和主線程之間的通信。我們先來(lái)了解一下官方關(guān)于 NSThread 的線程間通信的方法。

    1 2 3 4 5 6 7 8 9 10 11 12 13 // 在主線程上執(zhí)行操作 - (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait; - (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait modes:(NSArray<NSString *> *)array; // equivalent to the first method with kCFRunLoopCommonModes// 在指定線程上執(zhí)行操作 - (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(id)arg waitUntilDone:(BOOL)wait modes:(NSArray *)array NS_AVAILABLE(10_5, 2_0); - (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(id)arg waitUntilDone:(BOOL)wait NS_AVAILABLE(10_5, 2_0);// 在當(dāng)前線程上執(zhí)行操作,調(diào)用 NSObject 的 performSelector:相關(guān)方法 - (id)performSelector:(SEL)aSelector; - (id)performSelector:(SEL)aSelector withObject:(id)object; - (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2;

    ?

    下面通過(guò)一個(gè)經(jīng)典的下載圖片 DEMO 來(lái)展示線程之間的通信。具體步驟如下:

  • 開(kāi)啟一個(gè)子線程,在子線程中下載圖片。
  • 回到主線程刷新 UI,將圖片展示在 UIImageView 中。
  • DEMO 代碼如下:

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 /** * 創(chuàng)建一個(gè)線程下載圖片 */ - (void)downloadImageOnSubThread { // 在創(chuàng)建的子線程中調(diào)用downloadImage下載圖片 [NSThread detachNewThreadSelector:@selector(downloadImage) toTarget:self withObject:nil]; }/** * 下載圖片,下載完之后回到主線程進(jìn)行 UI 刷新 */ - (void)downloadImage { NSLog(@"current thread -- %@", [NSThread currentThread]);// 1. 獲取圖片 imageUrl NSURL *imageUrl = [NSURL URLWithString:@"https://ysc-demo-1254961422.file.myqcloud.com/YSC-phread-NSThread-demo-icon.jpg"];// 2. 從 imageUrl 中讀取數(shù)據(jù)(下載圖片) -- 耗時(shí)操作 NSData *imageData = [NSData dataWithContentsOfURL:imageUrl]; // 通過(guò)二進(jìn)制 data 創(chuàng)建 image UIImage *image = [UIImage imageWithData:imageData];// 3. 回到主線程進(jìn)行圖片賦值和界面刷新 [self performSelectorOnMainThread:@selector(refreshOnMainThread:) withObject:image waitUntilDone:YES]; }/** * 回到主線程進(jìn)行圖片賦值和界面刷新 */ - (void)refreshOnMainThread:(UIImage *)image { NSLog(@"current thread -- %@", [NSThread currentThread]);// 賦值圖片到imageview self.imageView.image = image; }

    ?

    2.5 NSThread 線程安全和線程同步

    線程安全:如果你的代碼所在的進(jìn)程中有多個(gè)線程在同時(shí)運(yùn)行,而這些線程可能會(huì)同時(shí)運(yùn)行這段代碼。如果每次運(yùn)行結(jié)果和單線程運(yùn)行的結(jié)果是一樣的,而且其他的變量的值也和預(yù)期的是一樣的,就是線程安全的。

    若每個(gè)線程中對(duì)全局變量、靜態(tài)變量只有讀操作,而無(wú)寫(xiě)操作,一般來(lái)說(shuō),這個(gè)全局變量是線程安全的;若有多個(gè)線程同時(shí)執(zhí)行寫(xiě)操作(更改變量),一般都需要考慮線程同步,否則的話就可能影響線程安全。

    線程同步:可理解為線程 A 和 線程 B 一塊配合,A 執(zhí)行到一定程度時(shí)要依靠線程 B 的某個(gè)結(jié)果,于是停下來(lái),示意 B 運(yùn)行;B 依言執(zhí)行,再將結(jié)果給 A;A 再繼續(xù)操作。

    舉個(gè)簡(jiǎn)單例子就是:兩個(gè)人在一起聊天。兩個(gè)人不能同時(shí)說(shuō)話,避免聽(tīng)不清(操作沖突)。等一個(gè)人說(shuō)完(一個(gè)線程結(jié)束操作),另一個(gè)再說(shuō)(另一個(gè)線程再開(kāi)始操作)。

    下面,我們模擬火車(chē)票售賣(mài)的方式,實(shí)現(xiàn) NSThread 線程安全和解決線程同步問(wèn)題。

    場(chǎng)景:總共有50張火車(chē)票,有兩個(gè)售賣(mài)火車(chē)票的窗口,一個(gè)是北京火車(chē)票售賣(mài)窗口,另一個(gè)是上?;疖?chē)票售賣(mài)窗口。兩個(gè)窗口同時(shí)售賣(mài)火車(chē)票,賣(mài)完為止。

    2.5.1 NSThread 非線程安全

    先來(lái)看看不考慮線程安全的代碼:

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 /** * 初始化火車(chē)票數(shù)量、賣(mài)票窗口(非線程安全)、并開(kāi)始賣(mài)票 */ - (void)initTicketStatusNotSave { // 1. 設(shè)置剩余火車(chē)票為 50 self.ticketSurplusCount = 50;// 2. 設(shè)置北京火車(chē)票售賣(mài)窗口的線程 self.ticketSaleWindow1 = [[NSThread alloc]initWithTarget:self selector:@selector(saleTicketNotSafe) object:nil]; self.ticketSaleWindow1.name = @"北京火車(chē)票售票窗口";// 3. 設(shè)置上海火車(chē)票售賣(mài)窗口的線程 self.ticketSaleWindow2 = [[NSThread alloc]initWithTarget:self selector:@selector(saleTicketNotSafe) object:nil]; self.ticketSaleWindow2.name = @"上?;疖?chē)票售票窗口";// 4. 開(kāi)始售賣(mài)火車(chē)票 [self.ticketSaleWindow1 start]; [self.ticketSaleWindow2 start];}/** * 售賣(mài)火車(chē)票(非線程安全) */ - (void)saleTicketNotSafe { while (1) { //如果還有票,繼續(xù)售賣(mài) if (self.ticketSurplusCount > 0) { self.ticketSurplusCount --; NSLog(@"%@", [NSString stringWithFormat:@"剩余票數(shù):%ld 窗口:%@", self.ticketSurplusCount, [NSThread currentThread].name]); [NSThread sleepForTimeInterval:0.2]; } //如果已賣(mài)完,關(guān)閉售票窗口 else { NSLog(@"所有火車(chē)票均已售完"); break; } } }

    運(yùn)行后部分結(jié)果為:

    可以看到在不考慮線程安全的情況下,得到票數(shù)是錯(cuò)亂的,這樣顯然不符合我們的需求,所以我們需要考慮線程安全問(wèn)題。

    2.5.2 NSThread 線程安全

    線程安全解決方案:可以給線程加鎖,在一個(gè)線程執(zhí)行該操作的時(shí)候,不允許其他線程進(jìn)行操作。iOS 實(shí)現(xiàn)線程加鎖有很多種方式。@synchronized、 NSLock、NSRecursiveLock、NSCondition、NSConditionLock、pthread_mutex、dispatch_semaphore、OSSpinLock、atomic(property) set/ge等等各種方式。為了簡(jiǎn)單起見(jiàn),這里不對(duì)各種鎖的解決方案和性能做分析,只用最簡(jiǎn)單的@synchronized來(lái)保證線程安全,從而解決線程同步問(wèn)題。

    考慮線程安全的代碼:

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 /** * 初始化火車(chē)票數(shù)量、賣(mài)票窗口(線程安全)、并開(kāi)始賣(mài)票 */ - (void)initTicketStatusSave { // 1. 設(shè)置剩余火車(chē)票為 50 self.ticketSurplusCount = 50;// 2. 設(shè)置北京火車(chē)票售賣(mài)窗口的線程 self.ticketSaleWindow1 = [[NSThread alloc]initWithTarget:self selector:@selector(saleTicketSafe) object:nil]; self.ticketSaleWindow1.name = @"北京火車(chē)票售票窗口";// 3. 設(shè)置上?;疖?chē)票售賣(mài)窗口的線程 self.ticketSaleWindow2 = [[NSThread alloc]initWithTarget:self selector:@selector(saleTicketSafe) object:nil]; self.ticketSaleWindow2.name = @"上?;疖?chē)票售票窗口";// 4. 開(kāi)始售賣(mài)火車(chē)票 [self.ticketSaleWindow1 start]; [self.ticketSaleWindow2 start];}/** * 售賣(mài)火車(chē)票(線程安全) */ - (void)saleTicketSafe { while (1) { // 互斥鎖 @synchronized (self) { //如果還有票,繼續(xù)售賣(mài) if (self.ticketSurplusCount > 0) { self.ticketSurplusCount --; NSLog(@"%@", [NSString stringWithFormat:@"剩余票數(shù):%ld 窗口:%@", self.ticketSurplusCount, [NSThread currentThread].name]); [NSThread sleepForTimeInterval:0.2]; } //如果已賣(mài)完,關(guān)閉售票窗口 else { NSLog(@"所有火車(chē)票均已售完"); break; } } } }

    運(yùn)行后結(jié)果為:

    省略一部分結(jié)果圖。。。

    可以看出,在考慮了線程安全的情況下,加鎖之后,得到的票數(shù)是正確的,沒(méi)有出現(xiàn)混亂的情況。我們也就解決了多個(gè)線程同步的問(wèn)題。

    2.6 線程的狀態(tài)轉(zhuǎn)換

    當(dāng)我們新建一條線程N(yùn)SThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];,在內(nèi)存中的表現(xiàn)為:

    當(dāng)調(diào)用[thread start];后,系統(tǒng)把線程對(duì)象放入可調(diào)度線程池中,線程對(duì)象進(jìn)入就緒狀態(tài),如下圖所示。

    當(dāng)然,可調(diào)度線程池中,會(huì)有其他的線程對(duì)象,如下圖所示。在這里我們只關(guān)心左邊的線程對(duì)象。

    下邊我們來(lái)看看當(dāng)前線程的狀態(tài)轉(zhuǎn)換。

    • 如果CPU現(xiàn)在調(diào)度當(dāng)前線程對(duì)象,則當(dāng)前線程對(duì)象進(jìn)入運(yùn)行狀態(tài),如果CPU調(diào)度其他線程對(duì)象,則當(dāng)前線程對(duì)象回到就緒狀態(tài)。
    • 如果CPU在運(yùn)行當(dāng)前線程對(duì)象的時(shí)候調(diào)用了sleep方法\等待同步鎖,則當(dāng)前線程對(duì)象就進(jìn)入了阻塞狀態(tài),等到sleep到時(shí)\得到同步鎖,則回到就緒狀態(tài)。
    • 如果CPU在運(yùn)行當(dāng)前線程對(duì)象的時(shí)候線程任務(wù)執(zhí)行完畢\異常強(qiáng)制退出,則當(dāng)前線程對(duì)象進(jìn)入死亡狀態(tài)。

    只看文字可能不太好理解,具體當(dāng)前線程對(duì)象的狀態(tài)變化如下圖所示。

    轉(zhuǎn)載于:https://my.oschina.net/u/3697347/blog/1648478

    總結(jié)

    以上是生活随笔為你收集整理的iOS多线程:『pthread、NSThread』详尽总结的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 黄色三级生活片 | 亚洲一区二区三区免费 | 农村黄色片 | 国产在线不卡视频 | 国产福利精品视频 | 亚洲性一区 | 日韩av无码一区二区三区不卡 | 国内精品久久久久久久久久久 | 日韩精品中文在线 | 波多野结衣精品在线 | 成人在线观看亚洲 | 男人av资源网 | 国产精品xxxxxx | 夜夜高潮夜夜爽国产伦精品 | 精品久久久无码中文字幕 | 91成人精品国产刺激国语对白 | 日韩精品视频在线 | 另类激情亚洲 | 亚洲精品在线观看免费 | 久久久久成人网站 | 美足av电影| av在线一区二区 | 欧美人与性囗牲恔配 | 91超碰在线 | 国精无码欧精品亚洲一区蜜桃 | 五月婷婷天堂 | aaaaa毛片| 国产精品调教 | 57pao成人国产永久免费视频 | 人人插人人爽 | 国产一级黄色录像 | 干美女少妇| 日韩精品网站 | 亚洲精品少妇久久久久久 | 国产草草 | 超鹏在线视频 | 欧美aⅴ在线观看 | 青青青青青青草 | 亚洲欧美精品一区二区 | 爱爱小视频免费看 | 亚洲精品一线二线三线 | 日韩精品1区2区 | av中文字幕av | 三年大全国语中文版免费播放 | 青春草视频在线免费观看 | 国产在线观看黄色 | 西川结衣在线观看 | 最新日韩中文字幕 | 伊人天堂av | 色哟哟视频网站 | 香港三级韩国三级日本三级 | 天天操天天干天天爱 | 欧美精品成人 | 精品国产一区二区三区在线 | 伊人久久久久久久久久久久久 | 日本三级网站在线观看 | 久久亚洲av午夜福利精品一区 | 五月婷婷综合在线 | 国产精品久久久久久亚洲伦 | 成人在线视频免费看 | 真人抽搐一进一出视频 | 自拍视频在线播放 | 日美韩一区二区三区 | 免费看欧美一级片 | 成年人黄色免费网站 | 国产精品久久久久久久免费观看 | 亚洲精品午夜精品 | 亚洲中文字幕无码专区 | 三年中文免费观看大全动漫 | 老司机福利院 | 日韩视频免费观看高清完整版 | 精品午夜久久 | 无码人妻久久一区二区三区 | 伊人久久精品 | 欧美污视频在线观看 | 国产在线一区不卡 | 国产人妻精品午夜福利免费 | 亚洲精品理论片 | 亚洲男人天堂网址 | 欧美日韩一二三四 | 337p粉嫩色噜噜噜大肥臀 | 中文字幕精品久久久 | 国产富婆一级全黄大片 | 久草热在线视频 | 草莓巧克力香氛动漫的观看方法 | 久久久夜色 | 成人av在线资源 | 影音先锋国产资源 | 日韩一级二级视频 | 第四色影音先锋 | 男人的影院 | 99久久精品免费看国产免费软件 | a天堂在线视频 | 一级做a爱视频 | 精品国产免费人成在线观看 | 国产91视频播放 | 99精品久久久久久中文字幕 | 精品国产av无码一区二区三区 | 污视频在线免费观看 |