犄角旮旯C/C++

指定线程运行任务

2018-08-17  本文已影响0人  cx7

使用场景

使用某些第三方库时,会遇到线程安全的问题.
如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();
}

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

上一篇 下一篇

猜你喜欢

热点阅读