如何使用C++20原子等待来等待多个值?

3z6pesqy  于 2023-05-30  发布在  其他
关注(0)|答案(1)|浏览(140)

C++20提供了原子等待,直到值发生变化。我们可以做的一件事是用原子等待替换条件变量。比如说

bool has_tasks{true};
std::condition_variable cv;
std::mutex mtx;

{
  std::uniqe_lock lock{mtx};
  // unblock if has_tasks is false
  cv.wait(lock, [](){ return !has_tasks; }) // someone will notify
  // ...
}

// equivalent
std::atomic<bool> has_tasks{true};
// unblock if has_tasks is false
has_tasks.wait(true); // someone will notify
// ...

一个线程将被阻塞,直到has_tasks变为false并且该线程得到通知;
但是,如果我想等待除一个值以外的所有值,该怎么办?通过使用条件变量,我可以做到:

size_t num_tasks{0};
std::condition_variable cv;
std::mutex mtx;
std::uniqe_lock lock{mtx};
{
 cv.wait(lock, [](){ return num_tasks == 0; })
}

// equivalent
std::atomic<size_t> num_tasks{0};
num_tasks.wait(/* how to wait on multiple values? */)

如果num_tasks为零,则线程将被解除阻塞。有没有办法用原子等待替换上面的条件变量?

qacovj5a

qacovj5a1#

不能使用一个对原子等待的调用来等待两个独立的事件。但是,您可以等待两次(或n次)来实现相同的效果。
下面的代码等待num_tasks递增两次(或设置为01以外的值),然后才允许线程完成。使用std::atomic,您不需要检查虚假唤醒,因为这是由std::atomic处理的,这简化了一点逻辑。

示例代码

#include <atomic>
#include <chrono>
#include <iostream>
#include <thread>

using namespace std::chrono_literals;
using std::cout, std::endl;

int main(int argc, const char *argv[]) {

    std::atomic<int> num_tasks{};

    auto th = std::thread([&]() {
        cout << "waiting on tasks" << endl;
        num_tasks.wait(0);
        cout << "one task ready" << endl;
        num_tasks.wait(1);
        cout << "two tasks ready" << endl;
    });

    std::this_thread::sleep_for(250ms);
    cout << "adding task" << endl;
    num_tasks = num_tasks + 1;
    num_tasks.notify_one();

    std::this_thread::sleep_for(250ms);
    cout << "adding task" << endl;
    num_tasks = num_tasks + 1;
    num_tasks.notify_one();

    if (th.joinable())
        th.join();
    return 0;
}

输出

waiting on tasks
adding task
one task ready
adding task
two tasks ready

相关问题