I am new to using multithreading and I am working on a program that handles mouse movement, it consists of two threads, the main thread gets the input and stores the mouse position in a fixed location and the child thread loops through that location to get the value. So how do I reduce CPU utilization, I am using conditional variables to achieve this, is there a better way to do this? It seems that adding a delay to the subthreads would also work
void Engine::InputManager::MouseMove(const MouseMoveEvent& ev)
{
cur_mouse_ev_.x_ = ev.x_;
cur_mouse_ev_.y_ = ev.y_;
cv_.notify_all();
}
void Engine::InputManager::ProcessInput(MouseMoveEvent* ev)
{
while (true)
{
cv_.wait(u_mutex_);
float dx = static_cast<float>(ev->x_ - pre_mouse_pos[0]) * 0.25f;
float dy = static_cast<float>(ev->y_ - pre_mouse_pos[1]) * 0.25f;
g_pGraphicsManager->CameraRotateYaw(dx);
pre_mouse_pos[0] = ev->x_;
pre_mouse_pos[1] = ev->y_;
}
}
CodePudding user response:
Using std::condition_variable
is a good and efficient way to achieve what you want.
However - you implementation has the following issue:
std::condition_variable
suffers from spurious wakeups. You can read about it here: https://en.wikipedia.org/wiki/Spurious_wakeup
The correct way to use a condition variable requires:
To add a variable (
bool
in your case) to hold the "condition" you are waiting for. The variable should be updated under a lock using the mutex.Again under a lock: calling
wait
in a loop until the variable satifies the condition you are waiting for. If a spurious wakeup will occur, the loop will ensure getting into the waiting state again. BTW -wait
mathod has an overload that gets a predicate for the condition, and loops for you.
You can see some code examples here: https://www.modernescpp.com/index.php/c-core-guidelines-be-aware-of-the-traps-of-condition-variables
A minimal sample that demonstrates the flow:
#include <thread>
#include <mutex>
#include <condition_variable>
std::mutex mtx;
std::condition_variable cond_var;
bool ready{ false };
void handler()
{
{
std::unique_lock<std::mutex> lck(mtx);
cond_var.wait(lck, []() { return ready; }); // will loop internally to handle spurious wakeups
}
// Handle data ...
}
void main()
{
std::thread t(handler);
// Prepare data ...
std::this_thread::sleep_for(std::chrono::seconds(3));
{
std::unique_lock<std::mutex> lck(mtx);
ready = true;
}
cond_var.notify_all();
t.join();
}
CodePudding user response: