使用場景
使用某些第三方庫時,會遇到線程安全的問題.
如OpenGL是非線程安全的 對OpenGL API的調(diào)用需要在同一個線程中完成.
實現(xiàn)原理
假定runOnAssignThread這個API 可以把任務(wù)投遞到指定線程運行
假設(shè)有多個線程 一個指定的任務(wù)運行線程 其余都是業(yè)務(wù)線程
在業(yè)務(wù)線程的運行過程中 將會調(diào)用到runOnAssignThread
就將任務(wù)投遞到了任務(wù)線程運行 業(yè)務(wù)線程不真正運行這個任務(wù)
偽代碼實現(xiàn):
任務(wù)運行函數(shù):
void runOnAssignThread(task task) {
if (當前就處于任務(wù)線程) {
task();//直接執(zhí)行任務(wù)
} else {
//把任務(wù)插入到一個隊列中
}
}
相應(yīng)的 在任務(wù)線程中 需要不斷的處理隊列中的任務(wù)
任務(wù)線程中:
for (;;) {
if (隊列有任務(wù)) {
task = list.front();//取出任務(wù)
task();//運行任務(wù)
}
}
大致的運行原理如此 實際上還有多線程對任務(wù)隊列的訪問同步稍计、任務(wù)線程的啟動和退出條件這些細節(jié)需要考慮
Object-C實現(xiàn)
iOS的GCD編程封裝了底層的線程操作
dispatch_sync可以直接指定在某個diapatch_queue_t中同步運行任務(wù)
這使得iOS的runOnAssignThread的實現(xiàn)容易了很多
dispatch_queue_t assignQueue; //此處假設(shè)這個隊列已經(jīng)申請好了
void runOnAssignQueue (void (^task)(void)) {
if (dispatch_get_current_queu() == assignQueue) {
task();
} else {
dispatch_sync(assignQueue, task);
}
}
C++ 實現(xiàn)
#include "runOnVideoQueue.hpp"
#include <iostream>
#include <thread>
#include <list>
#include <mutex>
#include <condition_variable>
typedef std::function<void()> task;
std::list<task> taskList;
std::mutex taskMutex;
std::condition_variable taskCond;
std::__thread_id videoQueueThreadID;
bool endFlag = false;
void runOnVideoQueue(task task) {
if (std::this_thread::get_id() == videoQueueThreadID) {
task();
} else {
std::unique_lock<std::mutex> lock(taskMutex);
taskList.push_back(task);
endFlag = true;
taskCond.notify_one();
}
}
void handleEventOnVideoQueue() {
for (;;) {
task task = nullptr;
{
std::unique_lock<std::mutex> lock(taskMutex);
taskCond.wait(lock, [] {
return endFlag;
});
if (taskList.empty()) {
std::cout << "error:empty task list";
continue;
}
task = taskList.front();
taskList.pop_front();
endFlag = false;
}
task();
}
}
void runOnVideoQueueTest() {
videoQueueThreadID = std::this_thread::get_id();
std::cout << "video queue thread id:" << videoQueueThreadID << std::endl;
std::thread otherQueue([] {
runOnVideoQueue([](){
std::cout << "add on other Queue but run on video queu biu biu biu" << std::endl;
});
});
otherQueue.join();
runOnVideoQueue([](){
std::cout << "run on video queu biu biu biu" << std::endl;
});
handleEventOnVideoQueue();
}
各個平臺上的實現(xiàn)原理基本是一致的 因為語言或者平臺特點有些許差別