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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

UE4异步编程专题 - 多线程

發布時間:2023/12/10 编程问答 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 UE4异步编程专题 - 多线程 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

專題的第二篇,我們聊聊UE4中的多線程的基礎設施。UE4中最基礎的模型就是FRunnable和FRunnableThread,FRunnable抽象出一個可以執行在線程上的對象,而FRunnableThread是平臺無關的線程對象的抽象。后面的篇幅會詳細討論這些基礎設施。

1. FRunnable

UE4為我們抽象FRunnable的概念,讓我們指定在線程上運行的一段邏輯過程。該過程通常是一個較為耗時的操作,例如文件IO;或者是常態為空閑等待(Idle)的循環,隨時等待新執行命令到來。

FRunnable為我們提供了四個重要的接口:

class CORE_API FRunnable { public:// ....virtual bool Init();virtual uint32 Run() = 0;virtual void Stop() {}virtual void Exit() {} };
  • Init是對FRunnable對象的初始化,它是由FRunnableThread在創建線程對象后,進入線程函數的時候立即被FRunnableThread調用的函數,并不能由用戶自己調用;
  • Run是Runnable過程的入口,同樣也是有FRunnableThread在Init成功后調用;
  • Exit是Run正常退出后,由FRunnableThread調用,進行對FRunnable對象的清理工作;
  • Stop是給用戶使用的接口,當我們覺得必要時停止FRunnable.
  • 例如一個空閑等待的FRunnable的實現:

    class MyRunnable : public FRunnable { public:MyRunnable(): RunningFlag(false), WorkEvent(FPlatformProcess::GetSynchEventFromPool()){}~MyRunnable(){FPlatformProcess::ReturnSynchEventToPool(WorkEvent);WorkEvent = nullptr;}bool Init() override{// ..if(!WorkEvent)return false;RunningFlag.Store(true);}void Run() override{while(RunningFlag.Load()){WorkEvent->Wait(MAX_uint32);if(!RunningFlag.Load())break;// ...}}void Stop() override{if(RunningFlag.Exchange(false))WorkEvent->Trigger();}void Exit() overrdie{// ...RunningFlag.Store(false);}void Notify(){WorkEvent->Trigger();}private:TAtomic<bool> RunningFlag;FEvent* WorkEvent;// ... };

    原子變量RunningFlag作為Runnable對象的運行狀態的標記,所以Run函數的主體就是在RunningFlag為ture的情況無限循環。WorkEvent是其他線程上執行的任務與MyRunnable交互的事件對象,通過Notify接口,可以喚醒它繼續執行。MyRunnable從Wait中醒來時,還會檢查一次RunningFlag,有可能是喚醒它的是Stop接口發出的事件。而Stop的實現,會判斷一下標識是否Runnable已經退出,而不用再次發出事件了。

    2. FRunnableThread

    FRunnable需要依附與一個FRunnableThread對象,才能被執行。例如,我們如果要執行第一節的空閑等待的Runnable:

    auto* my_runnable = new MyRunnable{};auto* runnable_thread = FRunnableThread::Create(my_runnable, "IdleWait");

    FRunnableThread是平臺無關的線程對象的抽象,它驅動著FRunnable的初始化,執行和清理,并提供了管理線程對象生命周期,線程局部存儲,親緣性和優先級等接口。

    class FRunnableThread {// ....// Tls 索引static uint32 RunnableTlsSlot;public:// 獲取Tls索引static uint32 GetTlsSlot();// 平臺無關的創建線程對象接口static FRunnableThread* Create(class FRunnable* InRunnable,const TCHAR* ThreadName,uint32 InStackSize,EThreadPriority InThreadPri,uint64 InThreadAffinityMask);public:// 設置線程優先級virtual void SetThreadPriority( EThreadPriority NewPriority ) = 0;// 掛起線程virtual void Suspend( bool bShouldPause = true ) = 0;// 殺死線程virtual bool Kill( bool bShouldWait = true ) = 0;// 同步等待線程退出virtual void WaitForCompletion() = 0;protected:// 平臺相關的線程對象初始化過程virtual bool CreateInternal(FRunnable* InRunnable, const TCHAR* InThreadName,uint32 InStackSize,EThreadPriority InThreadPri, uint64 InThreadAffinityMask) = 0; };

    UE4已經實現了各個平臺的線程對象。Win平臺使用的是系統Windows的Thread API. 而其他平臺是基于pthread,不同平臺實現上略有不同。通過編譯選項包含平臺相關的頭文件,并通過FPlatformProcess類型的定義來選擇相應平臺的實現。參見FRunnableThread::Create函數:

    FRunnableThread* FRunnableThread::Create(class FRunnable* InRunnable, const TCHAR* ThreadName,uint32 InStackSize,EThreadPriority InThreadPri, uint64 InThreadAffinityMask) {// ....NewThread = FPlatformProcess::CreateRunnableThread();if (NewThread){if (NewThread->CreateInternal(...))// .....}// .... }

    線程對象的創建,需要指定一個FRunnable對象的實例。

    FPlatformProcess::CreateRunnableThread就是簡單地new一個平臺相關的線程對象,而真正的初始化時在FRunnableThread::CreateInternal當中完成的。線程平臺相關的API差異很大,UE4的封裝盡可能地讓各個平臺的實現略有不同。

    系統API創建的線程對象,都以_ThreadProc作為入口函數。接下來是一系列的平臺相關的初始化工作,例如設置棧的大小,TLS的索引,親緣性掩碼,獲取平臺相關的線程ID等。之后,就會進入上一節我們提及的FRunnable的初始化流程中了。一個線程創建成功的時序圖如下:

    Win平臺的實現中,由于API的歷史原因需要_ThreadProc的調用約定是STDCALL. 因此Win平臺下的_ThreadProc函數,是一個轉發函數,轉發給了另外一個CDECL調用約定的函數FRunnableThreadWin::GuardedRun.

    3. Runnable or Callable

    UE4的多線程模型是Runnable和Thread,但是有不少C++庫,如標準庫,是Callable and Thread. 如果使用標準庫的std::thread:

    int main(void) {std::thread t{ [](){ std::cout << "Hello Thread." } };t.join();return 0; }

    暫時忽略標準庫thread簡陋的設施,Callable和Runnable這兩個模型是可以等價的,也就是他們可以相互表達。

    例如我們可以用UE4的設施,實現類似std::thread的FThread(UE4已經實現了一個):

    class FThread final : public FRunnable { public:template <typename Func, typename ... Args>explicit FThread(Func&& f, Args&& ... args): Callable(create_callable(std::forward<Func>(f), std::forward<Args>(args)...)), Thread(FRunnableThread::Create(this, "whatever")){if(!Thread)throw std::runtime_error{ "Failed to create thread!" };}void join(){Thread->WaitForCompletion();}virtual uint32 Run() override{Callable();return 0;}private:template <typename Func, typename ... Args>static auto create_callable(Func&& f, Args&& ... args) noexcept{// 為了簡單起見用了20的特性,如果是17標準以下的話,用tuple也能辦到。// Eat return typereturn [func = std::forward<Func>(f), ... args = std::forward<Args>(args)](){std::invoke(func, std::forward<Args>(args...));};}private:TFunction<void()> Callable;FRunnableThread* Thread; };

    我們還可以用std::thread和一些封裝,來實現一個的RunnableThread. 下面是一個簡單的實現:

    class RunnableThread { public:explicit RunnableThread(FRunnable* runnable): runnable_(runnable), inited_(false), init_result_(false), thread_(&RunnableThread::Run, this){std::unique_lock<std::mutex> lock{ mutex_ };cv_.wait(lock, [this](){ return inited_; });}protected:void Run(){auto result = runnable_->Init();{std::unique_lock<std::mutex> lock{ mutex_ };inited_ = true;init_result_ = result;}cv_.notify_one();if(result){runnable_->Run();runnable_->Exit();}}private:FRunnable* runnable_;bool inited_;bool init_result_;std::thread thread_;std::mutex mutex_;std::condition_variable cv_; };

    雖然筆者不喜歡面向對象的設計(OOD),但UE4的FRunnable和FRunnaableThread實現得確實挺不錯。沒有很重的框架束縛,并且FRunnable也有著跟callable一樣的表達能力,并且FRunnableThread封裝了各個平臺線程庫幾乎所有的功能特性。總體上來說,比標準庫的thread設施更齊全。

    4. 小結

    UE4中的多線程模型用一句話概括為: A FRunnable runs on a FRunnableThread.

    FRunnable是邏輯上的可執行對象的概念的抽象。對于一個具體的可執行對象的實現,用戶需要實現Init和Exit接口,對Runnable需要的系統資源進行申請和釋放;用戶需要實現Run來控制Runnable的執行流程,并在需要的情況下實現Stop接口,來控制Runnable的退出。

    FRunnableThread是UE4提供的平臺無關的線程對象的抽象,并提供了控制線程對象生命周期和狀態的接口。UE4實現了常見所有平臺的線程對象,實現細節對用戶透明。

    除此之外,本文還討論了Runnable與Callable兩種模型,并且它們具有相同的表達能力。

    這個系列的下一篇,將會討論FQueuedThreadPool. 它是由FRunnable及FRunnableThread組合實現的,用于執行任務隊列的線程池。

    總結

    以上是生活随笔為你收集整理的UE4异步编程专题 - 多线程的全部內容,希望文章能夠幫你解決所遇到的問題。

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

    主站蜘蛛池模板: 中文字幕国产视频 | 天堂草在线观看 | 国产成年人 | 69免费| 亚洲精品色午夜无码专区日韩 | 日韩无码精品一区二区 | 国产成人一区二区三区电影 | www.色天使 | 成人做爰www免费看视频网站 | 黄网视频在线观看 | 婷婷开心激情网 | 黄色一级一级 | 成人羞羞国产免费 | 久久久三区 | 久久九九爱 | 国产精品自拍网 | 在线看片一区二区 | 日本一区二区三区四区在线观看 | 狠狠爱av | 香蕉精品在线 | 国产精品久久久久久在线观看 | 国产精品区一区二区三 | 亚洲视频在线播放免费 | √天堂| 欧美人和黑人牲交网站上线 | 日p免费视频 | 国精品无码人妻一区二区三区 | 真人毛片视频 | 亚洲视频一区二区三区在线观看 | 成人做爰69片免费观看 | 中文字幕第80页 | 99久视频| 看特级毛片 | 五月婷婷天堂 | 香蕉综合视频 | 久久男人 | 欧美精品18videosex性欧美 | 少妇人妻偷人精品无码视频新浪 | 99亚洲精品| 亚洲三级视频在线观看 | 一区二区三区视频在线观看 | 男女做爰猛烈吃奶啪啪喷水网站 | av最新天堂 | 天堂аⅴ在线最新版在线 | 懂色aⅴ国产一区二区三区 亚洲欧美国产另类 | 可以免费观看的毛片 | 五月天天 | 二级毛片| 亚洲AV成人无码精品久久盆瓶 | 先锋影音av中文字幕 | 色婷婷aⅴ | 日韩Av无码精品 | 不卡成人 | 人妻少妇被粗大爽9797pw | 国产一区二区三区黄片 | 成人在线高清视频 | 国产福利小视频在线观看 | 国产精品sm调教免费专区 | 欧美videossex另类 | 精品成人av一区二区在线播放 | 黄色片在线免费 | 国产91丝袜在线播放 | 亚洲专区中文字幕 | a级黄色小视频 | 一区二区视频在线观看免费 | 99av视频| 中文字幕一区二区在线视频 | 精品日韩视频 | 色一情 | 日本黄网免费 | 亚洲妇女av| 日韩激情网址 | 秋霞网一区二区三区 | 日本a级片在线播放 | 国产美女在线免费观看 | 七七久久 | 中出在线观看 | 岛国av电影在线观看 | 中文字幕啪啪 | 欧美人与动牲交xxxxbbbb | 麻豆av电影网 | 男女日批在线观看 | 久久不雅视频 | 好看的中文字幕av | 91福利在线免费观看 | 亚洲午夜久久久久久久久久久 | 国产精品美女毛片真酒店 | 伊人精品久久 | 日本黄在线 | 成人黄色电影网址 | 蓝牛av | www.好了av.com| 91国偷自产一区二区三区老熟女 | 中文字幕一区二区三区在线观看 | 黄色片毛片 | 中文字幕十一区 | 九色视频网 | 久久久久久久国产精品毛片 | 久久免费看少妇 |