Примечание: я приведу примеры на C ++, но я считаю, что мой вопрос не зависит от языка 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 не требует их (во 2-м коде я не использовал их для код для компиляции)? (я не знаю, то же самое в других языках, поэтому этот вопрос может быть C ++ - уточняется c.)