美文网首页犄角旮旯C/C++
指定线程运行任务

指定线程运行任务

作者: cx7 | 来源:发表于2018-08-17 18:57 被阅读0次

    使用场景

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

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

    相关文章

      网友评论

        本文标题:指定线程运行任务

        本文链接:https://www.haomeiwen.com/subject/jrvtiftx.html