国产av一二三区|日本不卡动作网站|黄色天天久久影片|99草成人免费在线视频|AV三级片成人电影在线|成年人aV不卡免费播放|日韩无码成人一级片视频|人人看人人玩开心色AV|人妻系列在线观看|亚洲av无码一区二区三区在线播放

網(wǎng)易首頁 > 網(wǎng)易號 > 正文 申請入駐

UE5多線程|FRunnableThread

0
分享至


【USparkle專欄】如果你深懷絕技,愛“搞點研究”,樂于分享也博采眾長,我們期待你的加入,讓智慧的火花碰撞交織,讓知識的傳遞生生不息!

這是侑虎科技第1908篇文章,感謝作者南京周潤發(fā)供稿。歡迎轉(zhuǎn)發(fā)分享,未經(jīng)作者授權(quán)請勿轉(zhuǎn)載。如果您有任何獨到的見解或者發(fā)現(xiàn)也歡迎聯(lián)系我們,一起探討。(QQ群:793972859)

作者主頁:

https://www.zhihu.com/people/xu-chen-71-65

UE游戲包與編輯器中都有眾多線程,多線程可以充分利用CPU多核特性,提升游戲表現(xiàn),而且現(xiàn)代CPU核數(shù)越來越多,游戲多線程就更有必要了。

一、線程類型

線程可分為專用線程和線程池中線程。

專用線程為GameThread,RenderThread,StatsThread等,它們各自都干專門的事情,比如GameThread用于驅(qū)動游戲邏輯,RenderThread用于渲染,StatsThread用于干性能分析。在事情干完后會進入阻塞狀態(tài),不消耗CPU資源。

線程池線程包括PoolThread和TaskGraphThread,每個線程用于干多種異步任務(wù)。游戲中許多任務(wù)并發(fā)量大,但持續(xù)時間短,比如求解動畫藍圖,每幀都開幾個線程求解,求解完再銷毀線程無疑很浪費。另外有很多瑣碎的多線程任務(wù),單獨為它們開線程也很浪費。因此UE使用了線程池,池中線程會循環(huán)利用,不斷執(zhí)行不同的異步任務(wù),當沒有任務(wù)時也處于阻塞狀態(tài)。

使用多線程時,UE已對底層平臺接口進行了封裝,開發(fā)者無需關(guān)注平臺差異,直接使用UE提供的統(tǒng)一接口即可。

常用的多線程方式包括:RunnableThread、ThreadPool 和 TaskGraph。這三者在底層線程的實現(xiàn)機制上有所不同,對外提供的接口種類豐富,部分接口還支持通過參數(shù)指定所使用的線程實現(xiàn)方式。

二、FRunnable & FRunnableThread

基本的線程使用方式為FRunnable與FRunnableThread的組合,用于創(chuàng)建專用線程,比如AsyncLoadingThread與渲染線程等。FRunnable負責邏輯,F(xiàn)RunnableThread負責具體線程,線程承載了邏輯,兩者一一對應,好處是上層邏輯與底層平臺接口分離。

FRunnable

FRunnable類本身代表一個抽象的“可運行”對象,只有幾個接口,不涉及線程細節(jié),是我們寫邏輯的地方,理論上可以在任意線程執(zhí)行。

接口如下:

  • Init Runnable的初始化,初始化可能成功,可能失敗,失敗會立即返回,線程結(jié)束。

  • Run執(zhí)行邏輯主體,初始化成功后執(zhí)行。

  • Exit Run中任務(wù)執(zhí)行完后的正常退出接口,執(zhí)行清理操作。

  • Stop由其他線程調(diào)用,用于中途停止該Runnable以及背后的線程,但具體如何停止要我們自己實現(xiàn)。

  • GetSingleThreadInterface,當UE強制單線程模式時,返回用于Tick執(zhí)行的實例,用的不多。

上述接口不用我們調(diào)用,對應線程創(chuàng)建好后會自動調(diào)用。

示例FAsyncloadingThread:

該類用于處理異步資源加載,會另開一個線程加載資源,繼承了FRunnable,內(nèi)部的Thread變量存儲線程。


Init函數(shù)沒做什么,Run函數(shù)如下:


主體是一個while循環(huán),StopTaskCounter是循環(huán)退出條件,為Atomic計數(shù)器,當未被設(shè)置時就不斷處理加載,被設(shè)置后即退出。

Stop函數(shù)如下,會設(shè)置StopTaskCounter變量:


創(chuàng)建線程,啟動Run邏輯。

只需要下面一行代碼即可,詳細會在下文介紹:

FRunnableThread

FRunnableThread是平臺線程的抽象,也是基類,與平臺相關(guān)的線程操作由多個子類完成,包括:

  • FRunnableThreadWin

  • FRunnableThreadUnix

  • FRunnableThreadApple

  • FRunnableThreadAndroid

我們不需要繼承和修改這些類,使用即可。

成員變量:

  • FString ThreadName:線程名。

  • FRunnable* Runnable:對應Runnable。

  • FEvent* ThreadInitSyncEvent:同步的Event。

  • EThreadPriority ThreadPriority:線程優(yōu)先級,UE自己抽象了幾個枚舉。

接口:

  • Kill:結(jié)束線程,UE建議不要用操作系統(tǒng)的Kill接口,強殺線程會導致泄露和死鎖,應該調(diào)用Runnable的Stop方法。

  • WaitForCompletion:忙等,直到線程執(zhí)行完。

  • Suspend:讓線程掛起或繼續(xù)執(zhí)行。

  • SetThreadPriority:設(shè)置線程優(yōu)先級。

FRunnableThreadWin

看下常見的Windows平臺子類如何實現(xiàn)。

Windows平臺的線程為內(nèi)核對象,通過HANDLE持有索引,這里的Thread就是底層的線程。


Kill方法內(nèi)調(diào)用了Runnable的Stop,該函數(shù)由我們自己實現(xiàn),然后可選忙等,最后調(diào)用操作系統(tǒng)的CloseHandle方法釋放線程內(nèi)核對象。


Windows有TerminateThread方法可以直接結(jié)束線程,但平常不推薦調(diào)用,有以下幾個原因:

  • 線程函數(shù)中C++對象的析構(gòu)函數(shù)不會被執(zhí)行;

  • 線程棧不會被清理,除非調(diào)用TerminateThread的線程結(jié)束。這是Windows有意為之,加入其他在運行的線程要引用被“殺死”線程堆棧上的值,就會引起非法內(nèi)存訪問;

  • DLL通常會在線程終止時收到通知,但TerminateThread會導致DLL收不到通知,從而不執(zhí)行正常的清理工作。

Suspend方法調(diào)用兩個操作系統(tǒng)接口,掛起和恢復:


SetThreadPriority方法同樣調(diào)用了操作系統(tǒng)接口,只是要做優(yōu)先級轉(zhuǎn)換,Windows平臺線程優(yōu)先級為0-31,31最高。


Windows中WaitForSingleObject可以實現(xiàn)WaitForCompletion效果:


三、創(chuàng)建線程

使用靜態(tài)方法Create可創(chuàng)建FRunnableThread和底層線程:


  • InStack為線程棧大?。?/p>

  • InThreadPri為線程優(yōu)先級;

  • InThreadAffinityMask為線程的CPU運行偏好,一般用默認值;

  • InCreateFlags也一般用默認值。

函數(shù)內(nèi)部首先創(chuàng)建NewThread對象,Windows平臺即FRunnableThreadWin。如果當前設(shè)置了強制單線程模式,還可選創(chuàng)建FakeThread,通過Tick驅(qū)動執(zhí)行。


之后進入CreateInternal函數(shù),調(diào)用操作系統(tǒng)接口創(chuàng)建線程。把Runnable屬性設(shè)置為傳入的InRunnable,然后把線程相關(guān)參數(shù)轉(zhuǎn)化為適配當前操作系統(tǒng)的參數(shù),調(diào)用CreateThread Win32API創(chuàng)建線程,線程執(zhí)行的函數(shù)為_ThreadProc。同時注意到CREATE_SUSPENDED參數(shù),線程創(chuàng)建后默認為掛起狀態(tài),執(zhí)行了后面的ResumeThread,才會讓改線程運行。ThreadInitSyncEvent用于等待線程的Init執(zhí)行完畢,執(zhí)行完后調(diào)用線程才會繼續(xù)。


_ThreadProc函數(shù)先向UE的線程管理類注冊改線程,然后進入FRunnableThreadWin::Run函數(shù),真正開始邏輯,注意這個Run函數(shù)和FRunnable的Run毫無關(guān)系。

首先調(diào)用Runnable的Inti函數(shù),之后觸發(fā)ThreadInitSyncEvent,通知調(diào)用線程繼續(xù)。然后執(zhí)行最主要的Runnable->Run,等Run自動結(jié)束了,再調(diào)用Runnable->Exit做清理。最后返回ExitCode,改線程終止。



四、使用方式

Runnable有多種使用方式:

1. 手動創(chuàng)建FRunnable和FRunnableThread

可參考前面的FAsyncLoadingThread,適合一個長期任務(wù),而且工作量大。

2. Async函數(shù)

有時我們只想在其他線程中執(zhí)行一個短期任務(wù),線程生命周期不長,此時專門創(chuàng)建一個Runnable子類,并手動創(chuàng)建一個Thread有些繁瑣。引擎提供了Async函數(shù),可以只提供我們想要執(zhí)行的Lambda函數(shù),引擎為我們創(chuàng)建一個Thread,或者從線程池中選擇一個Thread來執(zhí)行邏輯。

使用例子:


第一個參數(shù)用于指定線程模式。

Async函數(shù)定義如下:


第一個參數(shù)為線程執(zhí)行方式,第二個為傳入的函數(shù)對象,第三個為執(zhí)行完的回調(diào)。

線程執(zhí)行方式Execution有如下幾種取值:

  • TaskGraph:在TaskGraph框架下執(zhí)行,會在線程池選一個線程,適合短任務(wù)。

  • TaskGraphMainThread:與上面類似,但會用主線程。

  • Thread:創(chuàng)建一個新線程執(zhí)行,適合長任務(wù)。

  • ThreadIfForkSate:不知。

  • ThreadPool:在GlobalThreadPool中選一個線程執(zhí)行。

  • LargeThreadPool:與上面類似,在LargeThreadPool選線程執(zhí)行,僅Editor下可用。

這里我們只關(guān)注Thread模式,處理分支如下:


創(chuàng)建了一個TAsyncRunnable對象,把Function和Promise傳入其中,Promise可理解為上面的CompletionCallback,然后通過FRunnableThread::Create接口創(chuàng)建新線程,執(zhí)行該Runnable。

TAsyncRunnable是一種特殊類型,它接收一個Function、Promise或Future作為參數(shù)。觀察其Run方法:在SetPromise時會執(zhí)行我們指派的任務(wù)。這個FRunnable和FRunnableThread對象是匿名的,外部代碼僅進行New而不Delete,其生命周期由TAsyncRunnable自身托管。具體的清理做法是將刪除操作提交至任務(wù)隊列(TaskGraph)。之所以不立即Delete,是因為此時Run函數(shù)可能尚未執(zhí)行完畢,立即Delete自身可能導致異常情況。


3. AsyncThread函數(shù)

和Async函數(shù)類似,內(nèi)部都用TAsyncRunnable實現(xiàn),不過它是專門創(chuàng)建匿名線程來執(zhí)行任務(wù)的,因此參數(shù)中增加了線程優(yōu)先級選項,這種用法引擎中不多。


五、線程同步工具

多線程環(huán)境下線程同步是個問題,UE提供了多種線程同步工具。

Atomics

Atomics可以原子的改變一個變量,相比鎖是更輕量的線程同步工具,線程不需要切換狀態(tài),提供更好的性能。從底層視角看,原子操作也是有鎖的,現(xiàn)代多核CPU會通過電路信號鎖Cache的方式來實現(xiàn)原子操作,只是這個過程很快。原子操作是一些多線程安全類型的實現(xiàn)基石。

使用場景

常見使用場景為實現(xiàn)多線程安全的計數(shù)器,比如SharedPtr里的引用計數(shù),下面的SharedReferenceCount類型就是std::atomic。


UE引擎提供了幾個類型,是對操作系統(tǒng)和C++ Atomic功能的封裝。

FPlatformAtomics

可對一個地址進行原子操作,如Add,Exchange。在不同平臺上會調(diào)用各自原子操作接口,Windows為Win32Api的_InterlockedExchange等接口。

示例


TAtomic

類似std::atomic,底層使用FPlatformAtomics實現(xiàn),提供相似接口。在UE5中,已被標記為DEPRECATED,推薦直接使用std::atomic。

FThreadSafeCounter

封裝的線程安全計數(shù)器,提供Increment、Decrement等接口,底層同樣使用FPlatformAtomics實現(xiàn)。

六、鎖

鎖可以創(chuàng)建一個臨界區(qū),在臨界區(qū)內(nèi)的代碼只允許一個線程執(zhí)行,其他線程等待。根據(jù)臨界區(qū)執(zhí)行時間,以及平臺實現(xiàn),鎖可能使線程從運行態(tài)切換到阻塞態(tài),讓出CPU,這個狀態(tài)切換也需要線程從用戶模式切換到內(nèi)核模式,切換時間大概1000個CPU周期。因此鎖是較重的線程同步工具。

FCriticalSection

UE提供了FCriticalSection作為各平臺鎖的封裝。

Windows平臺底層使用CriticalSection實現(xiàn),稱為關(guān)鍵段,Windows平臺上也有互斥量Mutex,但CriticalSection相比Mutex速度更快。進入臨界區(qū)需要調(diào)用EnterCriticalSection,其內(nèi)部會先用原子操作interlocked檢查是否能訪問資源,如果能訪問,就接著運行,這個速度很快。如果不能訪問,通常先Spin忙等一小段時間,若還不能訪問資源,再使用Event內(nèi)核對象進入阻塞態(tài)。當臨界區(qū)比較短時,可以避免用戶模式到內(nèi)核模式的切換。因此Windows平臺會用CriticalSection。

Linux平臺底層使用pthread_mutex_t實現(xiàn)。

Windows實現(xiàn):

初始化CriticalSection,4000表示未獲取到鎖忙等的CPU周期。


加鎖


解鎖


示例

通常使用FScopeLock配合FCriticalSection使用,可以通過構(gòu)造函數(shù)與析構(gòu)函數(shù)機制,使作用域內(nèi)的代碼成為臨界區(qū)。


Event

Event用于多線程的同步,比如上文介紹的Windows線程創(chuàng)建,主線程在調(diào)用CreateThread后,調(diào)用ThreadInitSyncEvent->Wait(),等待新線程完成初始化工作,新建線程初始化后執(zhí)行ThreadInitSyncEvent->Trigger(),通知主線程繼續(xù)執(zhí)行。

Windows平臺底層使用Event內(nèi)核對象實現(xiàn)Event。Event有自動重置和手動重置概念,自動重置時,一個線程執(zhí)行Trigger后,只有一個Wait的線程會被喚醒繼續(xù)執(zhí)行,手動重置時,所有Wait的線程都會被喚醒,后續(xù)要手動調(diào)用重置函數(shù),才能使Event變?yōu)槲从|發(fā)狀態(tài)。通常都使用自動重置。

FEvent

UE使用FEvent類型表示一個Event,有Wait、Trigger、Reset等接口。而且Event是內(nèi)核對象,創(chuàng)建比較昂貴,因此UE使用EventPool來管理這些Event,根據(jù)ManualReset分成兩個Pool。

EventPool接口:


WindowsRunnableThread中使用方式:


文末,再次感謝南京周潤發(fā) 的分享, 作者主頁:https://www.zhihu.com/people/xu-chen-71-65, 如果您有任何獨到的見解或者發(fā)現(xiàn)也歡迎聯(lián)系我們,一起探討。(QQ群: 793972859 )。


近期精彩回顧





特別聲明:以上內(nèi)容(如有圖片或視頻亦包括在內(nèi))為自媒體平臺“網(wǎng)易號”用戶上傳并發(fā)布,本平臺僅提供信息存儲服務(wù)。

Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

相關(guān)推薦
熱點推薦
森澤佳奈——業(yè)界勞模,步兵巔峰,TH經(jīng)典,紙巾殺手!

森澤佳奈——業(yè)界勞模,步兵巔峰,TH經(jīng)典,紙巾殺手!

素然追光
2025-12-25 02:30:03
反華拜鬼、兩姓家奴!張本智和叫板中國僅五天,老底被全網(wǎng)扒光

反華拜鬼、兩姓家奴!張本智和叫板中國僅五天,老底被全網(wǎng)扒光

削桐作琴
2025-12-24 16:05:43
外賣員深夜接到訂單,地址是郊區(qū)公墓,開門的竟是失蹤的未婚妻

外賣員深夜接到訂單,地址是郊區(qū)公墓,開門的竟是失蹤的未婚妻

罪案洞察者
2025-12-22 11:12:39
哭窮炫富,“知三當三”,裝了10年的吉克雋逸,還是“自食惡果”

哭窮炫富,“知三當三”,裝了10年的吉克雋逸,還是“自食惡果”

顧史
2025-12-12 14:59:24
業(yè)界狂飆大嫂!水川潤:14年橫跳5社,空手道E杯女神殺瘋了!

業(yè)界狂飆大嫂!水川潤:14年橫跳5社,空手道E杯女神殺瘋了!

素然追光
2025-12-23 20:07:20
75:24!日本最新民調(diào)出爐,高市早苗兵敗如山倒,果不出中國意料

75:24!日本最新民調(diào)出爐,高市早苗兵敗如山倒,果不出中國意料

顧史
2025-12-24 10:41:48
大潰敗,現(xiàn)場響起劉煒下課聲,四媒體人發(fā)聲,質(zhì)疑劉煒發(fā)言和用人

大潰敗,現(xiàn)場響起劉煒下課聲,四媒體人發(fā)聲,質(zhì)疑劉煒發(fā)言和用人

南海浪花
2025-12-25 07:58:58
出嫁前3天彩禮漲到28.8萬后續(xù):男方堅持退婚,女子曝光已社死

出嫁前3天彩禮漲到28.8萬后續(xù):男方堅持退婚,女子曝光已社死

千言娛樂記
2025-12-13 18:34:13
央行終于出手,2026年2月1日起正式執(zhí)行!拒收現(xiàn)金正式納入嚴管!

央行終于出手,2026年2月1日起正式執(zhí)行!拒收現(xiàn)金正式納入嚴管!

今朝牛馬
2025-12-24 22:30:26
墊資數(shù)百萬改造承包高校餐廳,期限沒到無奈停業(yè),200多萬元餐費未付;校方:多部門商議決定不續(xù)簽

墊資數(shù)百萬改造承包高校餐廳,期限沒到無奈停業(yè),200多萬元餐費未付;校方:多部門商議決定不續(xù)簽

大風新聞
2025-12-23 23:43:09
闞清子前男友紀凌塵經(jīng)紀人緊急辟謠,真是怕啥來啥,太惡毒了!

闞清子前男友紀凌塵經(jīng)紀人緊急辟謠,真是怕啥來啥,太惡毒了!

TVB的四小花
2025-12-25 01:01:33
這局完勝!凱特王妃攜夏洛特公主四手聯(lián)彈,梅根母女認輸吧!

這局完勝!凱特王妃攜夏洛特公主四手聯(lián)彈,梅根母女認輸吧!

夜深愛雜談
2025-12-24 22:47:41
馬斯克個人凈資產(chǎn)飆升至7490億美元,約合5.28萬億元人民幣,活到80歲每天要花1.8億元才能花完

馬斯克個人凈資產(chǎn)飆升至7490億美元,約合5.28萬億元人民幣,活到80歲每天要花1.8億元才能花完

觀威海
2025-12-24 15:46:29
國民黨7名要員赴陸,賴清德沒想到:這只是鄭麗文的第一步

國民黨7名要員赴陸,賴清德沒想到:這只是鄭麗文的第一步

沙溪解說
2025-12-25 06:36:15
比恒大還慘!中國第二大民企倒了,負債7500億,創(chuàng)始人被帶走

比恒大還慘!中國第二大民企倒了,負債7500億,創(chuàng)始人被帶走

混沌錄
2025-12-24 20:11:11
1-0絕殺!中國隊勢不可擋,U23亞洲杯前7戰(zhàn)僅輸1場,抽到絕世好簽

1-0絕殺!中國隊勢不可擋,U23亞洲杯前7戰(zhàn)僅輸1場,抽到絕世好簽

侃球熊弟
2025-12-24 09:21:34
2019年,有3位正軍職的原武警少將轉(zhuǎn)為副部級干部,掌舵公安警校

2019年,有3位正軍職的原武警少將轉(zhuǎn)為副部級干部,掌舵公安警校

小圣雜談原創(chuàng)
2025-12-24 12:53:32
開拓者4分惜敗魔術(shù),2連敗!阿夫迪亞25+6+8,楊瀚森創(chuàng)NBA里程碑

開拓者4分惜敗魔術(shù),2連?。“⒎虻蟻?5+6+8,楊瀚森創(chuàng)NBA里程碑

球場沒跑道
2025-12-24 13:37:58
錯失塞梅尼奧!利物浦火速敲定替代者:6000萬求購多特邊鋒

錯失塞梅尼奧!利物浦火速敲定替代者:6000萬求購多特邊鋒

球事百科吖
2025-12-25 03:36:24
15歲英格蘭天才邊鋒脫穎而出,讓巴薩蠢蠢欲動,未來鋒線重要拼圖

15歲英格蘭天才邊鋒脫穎而出,讓巴薩蠢蠢欲動,未來鋒線重要拼圖

零度眼看球
2025-12-25 08:42:39
2025-12-25 09:03:00
侑虎科技UWA incentive-icons
侑虎科技UWA
游戲/VR性能優(yōu)化平臺
1532文章數(shù) 986關(guān)注度
往期回顧 全部

科技要聞

老板監(jiān)視員工微信只需300元

頭條要聞

牛彈琴:美國強烈干涉歐洲的內(nèi)政 歐洲人要氣炸了

頭條要聞

牛彈琴:美國強烈干涉歐洲的內(nèi)政 歐洲人要氣炸了

體育要聞

26歲廣西球王,在質(zhì)疑聲中成為本土得分王

娛樂要聞

懷孕增重30斤!闞清子驚傳誕一女夭折?

財經(jīng)要聞

美國未來18個月不對中國芯片加額外關(guān)稅

汽車要聞

“運動版庫里南”一月份亮相???或命名極氪9S

態(tài)度原創(chuàng)

藝術(shù)
手機
本地
旅游
公開課

藝術(shù)要聞

毛主席草書背后的故事:小練字者迷失,書法之路揭示真相。

手機要聞

11月單品銷量Top20:蘋果包圓前三,榮耀X70國產(chǎn)第一

本地新聞

云游安徽|一川江水潤安慶,一塔一戲一城史

旅游要聞

賞燈玩雪、民俗美食 內(nèi)蒙古多地文旅活動吸引八方游客

公開課

李玫瑾:為什么性格比能力更重要?

無障礙瀏覽 進入關(guān)懷版