我有一个由 2 个线程同时使用的类:一个线程将结果(一个接一个)添加到results
任务中,第二个线程处理results
已经存在的那些。
// all members are copy-able
struct task {
command cmd;
vector<result> results;
};
class generator {
public:
generator(executor* e); // store the ptr
void run();
...
};
class executor {
public:
void run();
void add_result(int command_id, result r);
task& find_task(int command_id);
...
private:
vector<task> tasks_;
condition_variable_any update_condition_;
};
发射
// In main, we have instances of generator and executor,
// we launch 2 threads and wait for them.
std::thread gen_th( std::bind( &generator::run, gen_instance_) );
std::thread exe_th( std::bind( &executor::run, exe_instance_) );
生成器线程
void generator::run() {
while(is_running) {
sleep_for_random_seconds();
executor_->add_result( SOME_ID, new_result() );
}
}
执行线程
void executor::add_result( int command_id, result r ) {
std::unique_lock<std::recursive_mutex> l(mutex_);
task& t = this->find_task(command_id);
t.results.push_back(r);
update_condition_.notify_all();
}
void executor::run() {
while(is_running) {
update_condition_.wait(...);
task& t = this->find_task(SOME_ID);
for(result r: t.results) {
// no live updates are visible here
}
}
}
- 生成器线程每隔几秒添加一个结果。
- 执行线程是一个
executor
本身。它通过run
等待更新的方法运行,当更新发生时,它对结果起作用。
有几点需要注意:
- 任务向量可能很大;结果永远不会被处理;
- executor中的
for-each
循环获取它正在处理的任务,然后迭代结果,检查其中哪些是新的并处理它们。一旦处理,它们将被标记并且不会再次被处理。此处理可能需要一些时间。
当Executor Thread在添加另一个结果之前没有完成 for 循环时,就会出现问题 - 结果对象在 for 循环中不可见。由于Executor Thread正在工作,它不会注意到更新条件更新,不会刷新向量等。当它完成时(在 的一个已经不是实际的视图上工作tasks_
)它会再次挂在update_condition_
刚刚触发的 .. .
我需要让代码知道,它应该在完成后再次运行循环,或者对循环中可见的任务进行更改for-each
。这个问题的最佳解决方案是什么?