下面是我的调度程序的简化版本。单个线程按入队顺序处理 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;
}