Home > database >  Multi-threaded input processing
Multi-threaded input processing

Time:04-15

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:

  1. 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.

  2. 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:

  1. you could try using a semaphore, for (possibly) better performance
  2. instead of 2 threads, you could try using coroutines (standard or your own), for less memory consumption. A thread needs a stack frame, that's several MBytes at least. A coroutine may not need anything extra.
  • Related