3

I have one thread waiting for some event from various number of other thread, which depend on an event from this one thread to continue processing. How can I code to avoid busy looping?

More specifically, I have multiple threads that process their respective video frame and write it to a screen buffer (at different locations). After they are all finished, the one thread sends the buffer to draw then those threads wait for the draw call to finish and then proceed to their next frames.

This needs to be implemented in C++. C++ standard used is not limited.

EDIT: std::condition_variable doesn't seem to be the solution. Since it requires a mutex, and the number of threads (mutexes) is known at runtime, and I can't put mutexes in std::vector

The pseudocode of my program is like this:

drawThread:
    loop:
        for each processThread:
            wait for event
        draw()

processThread:
    loop:
        process()
        notify drawThread
        wait for draw to finish

EDIT: What I tried:

std::vector<std::atomic_bool> ready_flags;
std::atomic_bool finished_drawing = false;
void drawThread()
{
    while(true)
    { 
        CHECK:
        for(auto& flag: ready_flags)
        {
            if(!flag)
                goto CHECK;
        }
        draw();
        finished_drawing = true;
    }
}
void ProcessThread(int id)
{
    while(true)
    {
        process();
        finished_drawing=false;
        ready_flags[id] = true;
        while(!finished_drawing)
            ;
    }
}
sz ppeter
  • 1,698
  • 1
  • 9
  • 21
  • 3
    std::condition_variable https://en.cppreference.com/w/cpp/thread/condition_variable – Jeffrey Jun 15 '20 at 12:57
  • 1
    You only need one mutex for a condition variable. There is no law that says that every thread must always use its own, exclusive mutex. Doing so, actually, defeats the purpose of mutexes, since they are explicitly designed to be accessible by multiple threads. That's what mutexes are all about, after all. – Sam Varshavchik Jun 15 '20 at 13:00
  • 1
    Mutexes guard data against concurrent access from any number of threads. That said, you picked the tools (number of threads, communication method) already and now you have problems. However, maybe you should rather describe the goals, see also "XY Problem". – Ulrich Eckhardt Jun 15 '20 at 13:05
  • You say you can't use a vector of mutexes. In fact, [you can](https://stackoverflow.com/q/16465633/580083), just you need to avoid reallocation by proper `reserve`. Alternatively, if you don't know the number of threads/mutexes in advance, you can use `std::deque` or `std::list` of mutexes instead. The problem might be, that you cannot wait for multiple condition variables at once. But this problem is solvable, e.g., by introducing some (lock-free) queue of events accompanied by a single condition variable. – Daniel Langr Jun 15 '20 at 13:32
  • @DanielLangr Can you please elaborate according to my cases? Even just pseudocode is appreciated. – sz ppeter Jun 15 '20 at 14:03
  • @szppeter Sorry, but can't, at least in my free time. But I can suggest reading some good material about threading in C++. For example, _C++ Concurrency in Action_ is quite a good book. – Daniel Langr Jun 15 '20 at 18:03

1 Answers1

0

I sort of figuring out a working solution

const int processThreadCount;
std::atomic<int> ready_count{};
std::shared_mutex drawing_mutex;
std::conditional_variable_any can_draw;
void drawThread()
{
    while(true)
    { 
        std::unique_lock lk{drawing_mutex};
        canDraw.wait(lk, [&]{return ready_count==processThreadCount;};
        draw();
        ready_count=0;
    }
}
void ProcessThread(int id)
{
    while(true)
    {
        std::shared_lock lk{drawing_mutex};
        process();
        ++ready_count;
        can_draw.notify_one();
    }
}
sz ppeter
  • 1,698
  • 1
  • 9
  • 21