gpt4 book ai didi

multithreading - 条件变量真的需要另一个变量吗?

转载 作者:行者123 更新时间:2023-12-03 12:53:58 25 4
gpt4 key购买 nike

注意:我将在 C++ 中给出示例,但我相信我的问题与语言无关。如我错了请纠正我。

只是为了让你真正了解我——我想在这里学习的是 工具的作用没有别的了。不是它通常的用途,也不是惯例所说的,只是钝器的作用。在这种情况下 - 条件变量的作用。

到目前为止,在我看来,这是一种简单的机制,它允许线程等待(阻塞),直到其他线程向它们发出信号(解除阻塞)。仅此而已,无需处理关键部分访问或数据访问(当然它们可以用于此,但这只是程序员选择的问题)。此外,信令通常仅在发生重要事情时(例如加载数据)才完成,但理论上它可以随时调用。到目前为止正确吗?

现在,我看到的每个示例都使用条件变量对象(例如 std::condition_variable ),但还使用一些附加变量来标记是否发生了某些事情(例如 bool dataWasLoaded )。看看这个来自 https://thispointer.com//c11-multithreading-part-7-condition-variables-explained/ 的例子:

#include <iostream>
#include <thread>
#include <functional>
#include <mutex>
#include <condition_variable>
using namespace std::placeholders;
class Application
{
std::mutex m_mutex;
std::condition_variable m_condVar;
bool m_bDataLoaded;
public:
Application()
{
m_bDataLoaded = false;
}
void loadData()
{
// Make This Thread sleep for 1 Second
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
std::cout << "Loading Data from XML" << std::endl;
// Lock The Data structure
std::lock_guard<std::mutex> guard(m_mutex);
// Set the flag to true, means data is loaded
m_bDataLoaded = true;
// Notify the condition variable
m_condVar.notify_one();
}
bool isDataLoaded()
{
return m_bDataLoaded;
}
void mainTask()
{
std::cout << "Do Some Handshaking" << std::endl;
// Acquire the lock
std::unique_lock<std::mutex> mlock(m_mutex);
// Start waiting for the Condition Variable to get signaled
// Wait() will internally release the lock and make the thread to block
// As soon as condition variable get signaled, resume the thread and
// again acquire the lock. Then check if condition is met or not
// If condition is met then continue else again go in wait.
m_condVar.wait(mlock, std::bind(&Application::isDataLoaded, this));
std::cout << "Do Processing On loaded Data" << std::endl;
}
};
int main()
{
Application app;
std::thread thread_1(&Application::mainTask, &app);
std::thread thread_2(&Application::loadData, &app);
thread_2.join();
thread_1.join();
return 0;
}

现在,除了 std::condition_variable m_condVar它还使用了一个附加变量 bool m_bDataLoaded .但在我看来,线程执行 mainTask已通过 std::condition_variable m_condVar 通知数据已加载.为什么还要检查 bool m_bDataLoaded相同的信息?比较(没有 bool m_bDataLoaded 的相同代码):
#include <iostream>
#include <thread>
#include <functional>
#include <mutex>
#include <condition_variable>
using namespace std::placeholders;
class Application
{
std::mutex m_mutex;
std::condition_variable m_condVar;
public:
Application()
{
}
void loadData()
{
// Make This Thread sleep for 1 Second
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
std::cout << "Loading Data from XML" << std::endl;
// Lock The Data structure
std::lock_guard<std::mutex> guard(m_mutex);
// Notify the condition variable
m_condVar.notify_one();
}
void mainTask()
{
std::cout << "Do Some Handshaking" << std::endl;
// Acquire the lock
std::unique_lock<std::mutex> mlock(m_mutex);
// Start waiting for the Condition Variable to get signaled
// Wait() will internally release the lock and make the thread to block
// As soon as condition variable get signaled, resume the thread and
// again acquire the lock. Then check if condition is met or not
// If condition is met then continue else again go in wait.
m_condVar.wait(mlock);
std::cout << "Do Processing On loaded Data" << std::endl;
}
};
int main()
{
Application app;
std::thread thread_1(&Application::mainTask, &app);
std::thread thread_2(&Application::loadData, &app);
thread_2.join();
thread_1.join();
return 0;
}
  • 现在我知道了虚假唤醒,它们单独需要使用一个额外的变量。我的问题是 - 他们是 他们只有 原因是什么?如果它们没有发生,是否可以只使用没有任何附加变量的条件变量(顺便说一句,这不会使“条件变量”这个名称用词不当)?
  • 另一件事是 - 使用附加变量不是条件变量也需要互斥锁的唯一原因吗?如果不是,其他原因是什么?
  • 如果需要额外的变量(出于虚假唤醒或其他原因),为什么 API 不需要它们(在第二个代码中我不必使用它们来编译代码)? (我不知道在其他语言中是否相同,所以这个问题 可能是 C++ 特有的。)
  • 最佳答案

    这不仅仅是关于虚假唤醒。

    当您调用 m_condvar.wait ,你怎么知道你等待的条件还没有发生?

    也许'loadData'已经在另一个线程中被调用了。当它调用 notify_one() ,什么也没发生,因为没有线程在等待。

    现在,如果您调用 condvar.wait ,您将永远等待,因为没有任何信号会通知您。

    原版没有这个问题,因为:

  • 如果 m_bDataLoaded为假,则知道数据没有加载,在m_bDataLoaded之后设置为真,调用者将发出条件信号;
  • 锁被持有,我们知道 m_bDataLoaded在发布之前不能在另一个线程中修改;
  • condvar.wait在释放锁之前会将当前线程放入等待队列,所以我们知道m_bDataLoaded将在我们开始等待后设置为 true,因此 notify_one在我们开始等待后也会被调用。

  • 要回答您的其他问题:
  • 是的,与其他变量的协调是条件变量与互斥锁相关联的原因。
  • API 不需要,比如说,一个 bool 变量,因为这并不总是你正在等待的那种条件。

  • 这种事情很常见,例如:
    Task *getTask() {
    //anyone who uses m_taskQueue or m_shutDown must lock this mutex
    unique_lock<mutex> lock(m_mutex);

    while (m_taskQueue.isEmpty()) {
    if (m_shutdown) {
    return null;
    }
    // this is signalled after a task is enqueued
    // or m_shutdown is asserted
    m_condvar.wait(lock);
    }
    return taskQueue.pop_front();
    }

    这里我们需要同样的关键保证,即线程在释放锁之前就开始等待,但是我们等待的条件更复杂,涉及到变量和单独的数据结构,并且有多种方式可以退出等待。

    关于multithreading - 条件变量真的需要另一个变量吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60917850/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com