指定线程运行任务

使用场景

使用某些第三方库时,会遇到线程安全的问题.
如OpenGL是非线程安全的 对OpenGL API的调用需要在同一个线程中完成.

实现原理

假定runOnAssignThread这个API 可以把任务投递到指定线程运行

假设有多个线程 一个指定的任务运行线程 其余都是业务线程
在业务线程的运行过程中 将会调用到runOnAssignThread
就将任务投递到了任务线程运行 业务线程不真正运行这个任务

伪代码实现:
任务运行函数:
void runOnAssignThread(task task) {
    if (当前就处于任务线程) {
        task();//直接执行任务
    } else {
        //把任务插入到一个队列中
    }
}

相应的 在任务线程中 需要不断的处理队列中的任务
任务线程中:
for (;;) {
    if (队列有任务) {
        task = list.front();//取出任务
        task();//运行任务
    }
}

大致的运行原理如此 实际上还有多线程对任务队列的访问同步、任务线程的启动和退出条件这些细节需要考虑

Object-C实现

iOS的GCD编程封装了底层的线程操作
dispatch_sync可以直接指定在某个diapatch_queue_t中同步运行任务
这使得iOS的runOnAssignThread的实现容易了很多
dispatch_queue_t assignQueue; //此处假设这个队列已经申请好了

void runOnAssignQueue (void (^task)(void)) {
    if (dispatch_get_current_queu() == assignQueue) {
        task();
    } else {
        dispatch_sync(assignQueue, task);
    }
}

C++ 实现

#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();
}

各个平台上的实现原理基本是一致的 因为语言或者平台特点有些许差别

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 173,956评论 25 709
  • 1、通过CocoaPods安装项目名称项目信息 AFNetworking网络请求组件 FMDB本地数据库组件 SD...
    阳明AI阅读 16,025评论 3 119
  • 泪凝于睫离情苦,妙手擦眼欲遮掩。 世间最大苦是于,莫过离别相聚难。 此去前方茫茫路,何时归期待论时。 远去...
    酒一一阅读 210评论 0 2
  • 读凤红邪的自卑等系列文章有感 最近一直头脑风暴,猛喝鸡汤,打鸡血。现...
    半日闲brx阅读 960评论 0 6