【问题标题】:Polling for a atomic variable (bool) in C++?在 C++ 中轮询原子变量(bool)?
【发布时间】:2017-06-28 01:09:14
【问题描述】:

我有一个线程修改一个原子变量 (bool) 和另一个线程想要轮询该变量。我的应用程序在thread A 中进行了很少的函数调用,并开始轮询一个特定的原子变量。 Thread B 不断读取一些外部应用程序 (application on dbus) 的状态并相应地修改一些原子变量。 Thread A 中的一个函数想要确保如果它返回,那么某些外部应用程序已将其状态更改为所需的状态,它将通过这些原子标志了解。

我的申请详情:

thread A 中的函数是start_scan() 函数,它使用dbus API 开始扫描附近的 BLE 设备。然而,即使start scan 调用成功但外部应用程序 (org.bluez) 仍然需要一些时间来更新它的属性 (Property: Discovering)。我还定义了像isScanning 这样的函数,它查询一些变量(在我的应用程序内部)以获取外部应用程序的当前状态。每当更新外部应用程序的属性时,它会通过dbus 上的PropertiesChanged 信号通知其他应用程序,是的,在成功调用start_scan 后,我需要一些时间(不到一秒)才能收到PropertiesChanged 信号进行扫描.所以,我想在我从start_scan 函数返回之前轮询我的本地原子标志(使用我自己的超时机制),这将确保如果有人在调用start_scan 后查询扫描状态,那么isScanning 将返回一个有效的状态。

我不能使用 condition_variable,因为我有很多需要同步的函数和标志。

问题:

std::atomic<bool> scanning_;

// Thread A
void start_scan()
{
    // Dbus methods call
    while (scanning_ == false) { // With some timeout
        // Timeout mechanism
    }
}

// Thread B receving asyn signals from DBus
void propertyUpdate(std::string name, bool value)
{
    if (name == "Discovering")
        scanning_ = value;

    ...
}

当线程 A 将轮询 scanning_ 标志时,线程 B 将收到 dbus 信号以更新 scanning_ 标志。我不确定Thread A 是否会阻塞线程 B,就好像它会不断读取标志并且我的标志是原子的?我想知道如果原子变量可用,等待原子变量访问的线程是如何安排的?

编辑:

我正在做这样的事情:

    void setter(bool value)
    {
        std::lock_guard<std::mutex lock(mutex_);
        member_ = value;
    }

    bool getter(void)
    {
        std::lock_guard<std::mutex lock(mutex_);
        return member_;
    }

    // Thread A is blocking on a class member value
    while (getter() == false);

    // Thread B will modify the class member when required
    setter(true);

我想知道由于在公共互斥体上调度阻塞线程而可能面临的问题。线程 A 是否有可能继续获取 mutex_ 而线程 B 将被永远阻塞。如果在线程 A 中的 getter 函数返回之后和线程 A 再次获取 mutex_ 之前未调度线程 B,则可能会发生这种情况。

【问题讨论】:

  • 你不能使用互斥体或信号量吗?
  • 轮询是对资源的浪费,标准不保证它永远有效。使用条件变量。
  • @n.m.: 你的意思是说如果我的线程轮询一个被其他线程修改的变量,我的线程不会看到更新吗?
  • 你能详细说明吗?
  • 如果一个线程正在轮询,则不能保证任何其他线程都有机会运行..

标签: c++ multithreading stdatomic


【解决方案1】:

如果您需要阻塞线程直到条件变为真(在您的情况下,scanning_ 有超时),那么您应该使用condition variables。这样一来,scanning_ 将只是一个普通变量,而不是原子变量,它会受到互斥体的保护。

(使用原子变量进行某些线程通信是可能的,但您不能仅使用原子变量使线程休眠。在您的示例中,start_scan 不断运行,占用 CPU 时间)

【讨论】:

  • 是的,但是我有几个用于轮询的变量,我不想为每个标志创建一个条件变量。
  • 目前,我没有时间阅读您更新的帖子,我只是回复您的评论。您不需要创建多个 condvar。当 任何 标志发生变化时,您应该调用 condvar.signal()。然后,在另一个线程中,在 condvar.wait() 返回后,您可以检查标志的值。抱歉,如果您不能使用此方法,我稍后会阅读您的帖子。
  • 无法使用 condvar 的确切原因是什么?正如我在之前的评论中所写,您可以使用所需的任何条件。你可以做任何你想等待的复杂表达式。在 EDIT 中,您仍然拥有 while(getter()==false),这会导致该线程 100% 使用。
猜你喜欢
  • 1970-01-01
  • 2010-09-08
  • 2011-01-16
  • 1970-01-01
  • 2021-09-20
  • 1970-01-01
  • 1970-01-01
  • 2017-10-21
  • 1970-01-01
相关资源
最近更新 更多