• 【WIP】Seastar框架学习


    初始化流程

    • create_scheduling_group: 创建sg(调度组)
    • init_scheduling_group: 初始化每个sg,在每个sg内会创建task队列

    主要结构体

    task队列

    • 固定长度:长度为cores数量;
        boost::container::static_vector, max_scheduling_groups()> _task_queues;
        task_queue_list _active_task_queues;
        task_queue_list _activating_task_queues;
    
    • 1
    • 2
    • 3

    add_task

        void add_task(task* t) noexcept {
            auto sg = t->group();
            auto* q = _task_queues[sg._id].get();
            bool was_empty = q->_q.empty();
            q->_q.push_back(std::move(t));
    #ifdef SEASTAR_SHUFFLE_TASK_QUEUE
            shuffle(q->_q.back(), *q);
    #endif
            if (was_empty) {
                activate(*q);
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    往task队列里添加任务:

    void schedule(task* t) noexcept {
        engine().add_task(t);
    }
    
    void schedule_urgent(task* t) noexcept {
        engine().add_urgent_task(t);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    用户层api使用:

    场景1:yield方法

    • yield()函数会将task通过schedule方法添加到task队列中,并返回了future,等待调度执行;
    future<>
    yield() noexcept {
        memory::scoped_critical_alloc_section _;
        auto tsk = make_task([] {});
        schedule(tsk);
        return tsk->get_future();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    场景2:在future中的使用

    在future函数中,make_ready()方法会调用schedule函数添加_task到task队列中:

    template 
    void promise_base::make_ready() noexcept {
        if (_task) {
            if (Urgent == urgent::yes) {
                ::seastar::schedule_urgent(std::exchange(_task, nullptr));
            } else {
                ::seastar::schedule(std::exchange(_task, nullptr));
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    make_ready是怎么使用的呢?

    • future和promise是相关关联的,即使其中一个或者两个都moved;
    • set_value或者set_exception调用时,future会变得ready,然后continuation会被attach到该future上,该future就被run起来;
        /// \brief Gets the promise's associated future.
        ///
        /// The future and promise will be remember each other, even if either or
        /// both are moved.  When \c set_value() or \c set_exception() are called
        /// on the promise, the future will be become ready, and if a continuation
        /// was attached to the future, it will run.
        future get_future() noexcept;
    
    	template
    	template
    	SEASTAR_CONCEPT( requires std::invocable )
    	void futurize::satisfy_with_result_of(promise_base_with_type&& pr, Func&& func) {
    	    using ret_t = decltype(func());
    	    if constexpr (std::is_void_v) {
    	        func();
    	        pr.set_value();
    	    } else if constexpr (is_future::value) {
    	        func().forward_to(std::move(pr));
    	    } else {
    	        pr.set_value(func());
    	    }
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    任务的调度

    void
    reactor::run_some_tasks() {
        if (!have_more_tasks()) {
            return;
        }
        sched_print("run_some_tasks: start");
        reset_preemption_monitor();
        update_lowres_clocks();
    
        sched_clock::time_point t_run_completed = now();
        STAP_PROBE(seastar, reactor_run_tasks_start);
        _cpu_stall_detector->start_task_run(t_run_completed);
        do {
            auto t_run_started = t_run_completed;
            insert_activating_task_queues();
            // 从r
            task_queue* tq = pop_active_task_queue(t_run_started);
            sched_print("running tq {} {}", (void*)tq, tq->_name);
            tq->_current = true;
            _last_vruntime = std::max(tq->_vruntime, _last_vruntime);
            // 真正的开始run task
            run_tasks(*tq);
            tq->_current = false;
            t_run_completed = now();
            auto delta = t_run_completed - t_run_started;
            account_runtime(*tq, delta);
            sched_print("run complete ({} {}); time consumed {} usec; final vruntime {} empty {}",
                    (void*)tq, tq->_name, delta / 1us, tq->_vruntime, tq->_q.empty());
            tq->_ts = t_run_completed;
            if (!tq->_q.empty()) {
                insert_active_task_queue(tq);
            } else {
                tq->_active = false;
            }
        } while (have_more_tasks() && !need_preempt());
        _cpu_stall_detector->end_task_run(t_run_completed);
        STAP_PROBE(seastar, reactor_run_tasks_end);
        *internal::current_scheduling_group_ptr() = default_scheduling_group(); // Prevent inheritance from last group run
        sched_print("run_some_tasks: end");
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
  • 相关阅读:
    电子统计台账:垂直流水账格式数据的导入
    科技图表AE
    Java计算百分比保留整数
    关于项目编译工具ninja、make、cmake的区别与优劣
    智能优化算法:白鲸优化算法-附代码
    甘特图组件DHTMLX Gantt示例 - 如何有效管理团队工作时间?(二)
    java计算机毕业设计游戏账号交易源程序+mysql+系统+lw文档+远程调试
    k8s--基础--24.3--efk--安装efk组件
    初识form表单
    mockito 的 InjectMocks 和 Mock 有什么区别?
  • 原文地址:https://blog.csdn.net/CRISPY_RICE/article/details/126030659