在主线程中工作时挂起后台线程吗?

我有一个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(我使用的)文档显示类似“如果没有线程正在向变量写入数据,则从任何线程读取该变量都是安全的”这样的说法-我没有看到它对只写一个线程,但同时读其他线程的情况。在后一种情况下,我认为不仅可能存在竞争条件,而且写入可能还完成了一半,因此读取可能会导致垃圾?

  • 据我所知,出于这个原因,我需要原子的,这就是为什么我有atomic_bool background_blocked的原因。在问这个问题之前,我实际上只是用相同的代码编写了非原子的bool background blocked-它仍然可以运行并且可以工作-但据我了解,我很幸运(或者不是很不幸),这是错误的..我是否理解这个权利吗?

  • 由于后台线程正在运行,因此我无法background_blocked = true进入主线程的锁内。我认为,除了原子原子之外,我还可以仅为bool background_blocked使用第二个互斥锁? atomic_bool是这里更好的选择吗?

  • 关于解锁/通知的顺序-如果我正确地阅读the docs,则必须在unlock之前先notify_one,否则notify可能会使后台线程尝试获取仍处于锁定状态的互斥锁失败,然后等待下一个可能永远不会到来的通知-只有这样,主线程才能解锁互斥锁..正确吗?

  • 很难确定代码是否正确,或者我不是很不幸,不会得到错误的结果。但是我认为我的设计正确,是我想要的吗?我没有找到更多的标准/惯用设计来解决我的问题-我是否使任何事情变得过于复杂/是否有更好的设计?

iCMS 回答:在主线程中工作时挂起后台线程吗?

暂时没有好的解决方案,如果你有好的解决方案,请发邮件至:iooj@foxmail.com
本文链接:https://www.f2er.com/1689706.html

大家都在问