0

下面是我的调度程序的简化版本。单个线程按入队顺序处理 packaged_tasks。

  • execute安排并等待任务完成
  • schedules将任务排入队列并立即返回给用户
  • drain简单地将一个空任务排入队列,其想法是一旦我们到达它,我们就知道所有先前调度的命令都已执行

问题:这里有什么保证drain不会被优化吗?我已经用几个编译器测试了这个示例程序,-O3但没有一个优化空 lambda 调用。是否有足够的可观察行为(mTasks列表的操作、同步屏障等)使该排水实现有效?标准是怎么说的?

class Scheduler {
public:
    void processTasks() {
        // Runs on separate thread
        // ... some synchronization here ignored
        while (!mTasks.empty()) {
            auto& tsk = mTasks.front();
            tsk();
            mTasks.pop_front();
        }
    }

    void addTask(std::packaged_task<void(void)> task) {
        std::unique_lock lck(mMutex);
        mTasks.emplace_back(std::move(task));
        mCond.notify_one();
    }

    auto schedule(std::function<void(void)> func) {
        std::packaged_task<void(void)> task{func};
        auto fut = task.get_future();
        addTask(std::move(task));
        return fut;
    }

    void execute(std::function<void(void)> func) {
        auto fut = schedule(std::move(func));
        fut.get();
    }

    void fireAndForget(std::function<void(void)> func) {
        schedule(std::move(func));
    }

    void drain() {
        execute([] {});
    }

    std::list<std::packaged_task<void(void)>> mTasks;
    std::mutex mMutex;
    std::condition_variable mCond;
};

int main() {
    Scheduler sched;
    std::jthread executor{&Scheduler::processTasks, &sched};

    int counter = 0;
    sched.fireAndForget([&] {
        counter++;
        std::this_thread::sleep_for(1s);
    });
    sched.fireAndForget([&] {
        counter++;
        std::this_thread::sleep_for(1s);
    });
    sched.fireAndForget([&] {
        counter++;
        std::this_thread::sleep_for(1s);
    });

    sched.drain();

    assert(counter == 3);

    return 0;
}
4

0 回答 0