c++ - 在主线程中工作时暂停后台线程?
问题描述
我有一个 GUI 读取/写入一些包含许多条目的数据,其中写入单个条目很快,但写入所有条目需要很长时间。
- 所有条目的写入应在启动后立即在后台线程中同时开始(某些属性只能在写入所有条目后显示)。
- 用户应该能够在主线程上请求一次读/写,而不必等待很长时间。即请求应该导致后台线程在完成其当前单次写入后等待
- 一旦主线程上的单个读/写完成,后台线程应该在暂停之前继续它离开的地方。
据我所知,我有一个正在运行和工作的解决方案,但这是我的第一个并发 C++ 代码,也许“它有效”并不是衡量正确性的最佳指标。
为了简化代码:
- 我从一些原始
data
向量开始,“写入”包括就地处理元素。 - 我可以询问一个元素
data
是否已经被处理(is_processed(...)
)
这是简化的代码:
// includes ..
using namespace std; // only to make the question less verbose
class Gui {
vector<int> data;
mutex data_mtx;
condition_variable data_cv;
atomic_bool background_blocked = false;
// ...
}
Gui::Gui() {
// some init work .. like obtaining the raw data
thread background_worker([this]{fill_data();});
background_worker.detach();
}
void Gui::fill_data() { // should only do processing work while main thread does not
unique_lock data_lock(data_mtx);
background_blocked = false;
for(auto& entry : raw_data) {
data_cv.wait(data_lock, [this]{return !background_blocked;});
if(!is_processed(entry)) proccess(entry);
}
}
int Gui::get_single_entry(int i) { // called by main thread - should respond immediately / pause background work
background_blocked = true;
unique_lock data_lock(data_mtx);
auto& entry = data[i];
if(!is_processed(entry)) process(entry);
const auto result = entry;
background_blocked = false;
data_lock.unlock();
data_cv.notify_one();
return result;
}
// ...
(一个无用但说明性的示例可能是data
仅包含偶数的原始示例,process(..)
添加1
到该数字,is_processed(..)
如果该数字是奇数则返回 true。只有在处理完所有内容后才能知道的属性可能是已处理数据中的素数 -例如process(..)
也可以增加一个素数计数器)
我想我主要不确定安全阅读。我现在找不到它,但是 gcc(我使用的)文档说“如果没有线程正在写入变量,则从任何线程读取变量都是安全的” - 我没有看到它说任何关于只有 1 个线程在写入,但其他线程同时在读取的情况。在后一种情况下,我假设不仅可能存在竞争条件,而且写入也可能是半完成的,因此读取可能会导致垃圾?
据我了解,出于这个原因,我需要原子,这就是为什么我有
atomic_bool background_blocked
. 在问这个问题之前,实际上我只是使用相同的代码进行了非原子bool background blocked
操作——它仍然可以运行和工作——但据我了解,我很幸运(或者不是不走运),这是错误的......我理解对了吗?由于后台线程正在运行,我无法
background_blocked = true
锁定主线程。我认为,除了原子之外,我还可以使用第二个互斥锁仅用于bool background_blocked
? 这里是atomic_bool
更好的选择吗?关于解锁/通知的顺序 - 如果我正确阅读了文档,我必须在此
unlock
之前notify_one
,否则通知可能会使后台线程尝试获取仍然锁定的互斥锁,失败,然后等待下一个可能永远不会出现的通知- 只有这样主线程才会解锁互斥锁..对吗?很难确定代码是否正确,或者我只是“不走运”得到错误的结果。但我认为我的设计是正确的,并且做了我想要的......是吗?我没有找到更多标准/惯用设计来解决我的问题 - 我是否过于复杂/是否有更好的设计?
解决方案
推荐阅读
- r - 使用现有的“日期”变量;将月份和星期变量添加到数据框中
- javascript - 如何在相邻中找到 3 个或更多相同类别的元素?
- c - 尝试构建结构的基本问题
- css - 始终居中固定项目
- javascript - Stripe Webhooks StripeSignatureVerificationError
- kotlin - 为什么函数不能在 Kotlin 中直接用作 lambda?
- c++ - dart: ffi 的 void 函数
- javascript - 命令“npm run dev”不起作用,我该怎么办?
- python - 将 PIP 与 systemctl 一起使用
- mysql - 缩小mysql表