frunnable為我們提供了四個重要的介面:
class core_api frunnable
virtual void exit() {}
};
init是對frunnable物件的初始化,它是由frunnablethread在建立執行緒物件後,進入執行緒函式的時候立即被frunnablethread呼叫的函式,並不能由使用者自己呼叫;
run是runnable過程的入口,同樣也是有frunnablethread在init成功後呼叫;
exit是run正常退出後,由frunnablethread呼叫,進行對frunnable物件的清理工作;
stop是給使用者使用的介面,當我們覺得必要時停止frunnable.
例如乙個空閒等待的frunnable的實現:
class myrunnable : public frunnable
~myrunnable()
bool init() override
void run() override
}void stop() override
void exit() overrdie
void notify()
private:
tatomicrunningflag;
fevent* workevent;
// ...
};
原子變數runningflag作為runnable物件的執行狀態的標記,所以run函式的主體就是在runningflag為ture的情況無限迴圈。workevent是其他執行緒上執行的任務與myrunnable互動的事件物件,通過notify介面,可以喚醒它繼續執行。myrunnable從wait中醒來時,還會檢查一次runningflag,有可能是喚醒它的是stop介面發出的事件。而stop的實現,會判斷一下標識是否runnable已經退出,而不用再次發出事件了。
frunnable需要依附與乙個frunnablethread物件,才能被執行。例如,我們如果要執行第一節的空閒等待的runnable:
auto* my_runnable = new myrunnable{};
auto* runnable_thread = frunnablethread::create(my_runnable, "idlewait");
frunnablethread是平台無關的執行緒物件的抽象,它驅動著frunnable的初始化,執行和清理,並提供了管理執行緒物件生命週期,執行緒區域性儲存,親緣性和優先順序等介面。
class frunnablethread
;
ue4已經實現了各個平台的執行緒物件。win平台使用的是系統windows的thread api. 而其他平台是基於pthread,不同平台實現上略有不同。通過編譯選項包含平台相關的標頭檔案,並通過fplatformprocess型別的定義來選擇相應平台的實現。參見frunnablethread::create函式:
frunnablethread* frunnablethread::create(
class frunnable* inrunnable,
const tchar* threadname,
uint32 instacksize,
ethreadpriority inthreadpri,
uint64 inthreadaffinitymask)
// ....
}
執行緒物件的建立,需要指定乙個frunnable物件的例項。
fplatformprocess::createrunnablethread就是簡單地new乙個平台相關的執行緒物件,而真正的初始化時在frunnablethread::createinternal當中完成的。執行緒平台相關的api差異很大,ue4的封裝盡可能地讓各個平台的實現略有不同。
系統api建立的執行緒物件,都以_threadproc作為入口函式。接下來是一系列的平台相關的初始化工作,例如設定棧的大小,tls的索引,親緣性掩碼,獲取平台相關的執行緒id等。之後,就會進入上一節我們提及的frunnable的初始化流程中了。乙個執行緒建立成功的時序圖如下:
win平台的實現中,由於api的歷史原因需要_threadproc的呼叫約定是stdcall. 因此win平台下的_threadproc函式,是乙個**函式,**給了另外乙個cdecl呼叫約定的函式frunnablethreadwin::guardedrun.
ue4的多執行緒模型是runnable和thread,但是有不少c++庫,如標準庫,是callable and thread. 如果使用標準庫的std::thread:
int main(void)
}; t.join();
return 0;
}
暫時忽略標準庫thread簡陋的設施,callable和runnable這兩個模型是可以等價的,也就是他們可以相互表達。
例如我們可以用ue4的設施,實現類似std::thread的fthread(ue4已經實現了乙個):
class fthread final : public frunnable
; }
void join()
virtual uint32 run() override
private:
template static auto create_callable(func&& f, args&& ... args) noexcept;}
private:
tfunctioncallable;
frunnablethread* thread;
};
我們還可以用std::thread和一些封裝,來實現乙個的runnablethread. 下面是乙個簡單的實現:
class runnablethread
; cv_.wait(lock, [this]());
}protected:
void run()
;inited_ = true;
init_result_ = result;
}cv_.notify_one();
if(result)
}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設施更齊全。
ue4中的多執行緒模型用一句話概括為: a frunnable runs on a frunnablethread.
frunnable是邏輯上的可執行物件的概念的抽象。對於乙個具體的可執行物件的實現,使用者需要實現init和exit介面,對runnable需要的系統資源進行申請和釋放;使用者需要實現run來控制runnable的執行流程,並在需要的情況下實現stop介面,來控制runnable的退出。
frunnablethread是ue4提供的平台無關的執行緒物件的抽象,並提供了控制線程物件生命週期和狀態的介面。ue4實現了常見所有平台的執行緒物件,實現細節對使用者透明。
除此之外,本文還討論了runnable與callable兩種模型,並且它們具有相同的表達能力。
UE4多執行緒
frunnable為我們提供了四個重要的介面 class core api frunnable virtual void exit init是對frunnable物件的初始化,它是由frunnablethread在建立執行緒物件後,進入執行緒函式的時候立即被frunnablethread呼叫的函式,...
UE4多執行緒任務系統詳解
首先,了解一下該系統重要的資料型別.1.fqueuedthreadpool 虛基類,佇列執行緒池,fqueuedthreadpoolbase繼承自fqueuedthreadpool,fqueuedthreadpoolbase維護了乙個tarrayqueuedwork 需要被執行的工作 tarraya...
UE4 簡單的執行緒
有些工作不適合在遊戲邏輯中進行,例如在一幀中進了過於複雜的計算的話,遊戲會卡頓,這個時候我們可以考慮在另外乙個執行緒中進行計算而不再遊戲的主線程中進行計算。include runnable.h include runnablethread.h 首先定義我們要執行的runnable,我們所有要執行的邏...