Multithreaded number printer in ordered manner On recent interview I was asked to write program that print &quot;Zero&quot; and &quot;One&quot; to stdout from different threads, but in ordered manner:
zero
one
zero
one
zero
one
...

Now I decided to write more generalized solution and this is my first attempt:
#include &lt;string&gt;
#include &lt;vector&gt;
#include &lt;mutex&gt;
#include &lt;initializer_list&gt;
#include &lt;condition_variable&gt;
#include &lt;thread&gt;
#include &lt;iostream&gt;

struct OrderNumberPrinter
{
    OrderNumberPrinter(const std::initializer_list&lt;std::string&gt;&amp; list)
        : m_len(list.size())
        , m_cv(list.size())
    {
        size_t num = 0;
        for(auto it = list.begin(); it != list.end(); ++it, ++num)
        {
            m_workers.emplace_back([this, num, message = *it](){
                while(true)
                {
                    std::unique_lock&lt;std::mutex&gt; lock(m_printLock);
                    m_cv[num].wait(lock, [this, num](){ return m_current == num; });
                    std::cout &lt;&lt; message &lt;&lt; &quot;\n&quot;;
                    std::this_thread::sleep_for(std::chrono::seconds(1));
                    ++m_current;
                    if (m_current == m_len)
                    {
                        m_current = 0;
                    }
                    m_cv[m_current].notify_one();
                }
            });
        }
    }

    ~OrderNumberPrinter()
    {
        for(auto&amp; w: m_workers)
        {
            if (w.joinable())
            {
                w.join();
            }
        }
    }
private:
    int m_len = 0;
    int m_current = 0;
    std::vector&lt;std::condition_variable&gt; m_cv;
    std::mutex m_printLock;
    std::vector&lt;std::thread&gt; m_workers;
};

int main(int argc, char* argv[])
{
    OrderNumberPrinter printer = {&quot;zero&quot;, &quot;one&quot;, &quot;two&quot;, &quot;three&quot;};
    return 0;
}
Here are some things that may help you improve your program.
If it has private members, it should be a class
The OrderNumberPrinter struct really should be a class because it has private member data.  See C.8
Use std::size_t rather than int
The values m_len and m_current should both probably be std::size_t rather than int, not least because they are compared to num and initialized with list.size() which are both explicitly std::size_t.
Exercise all functions
There is no way that the destructor ever gets called in the current code because there is no exit condition in the code.  For that reason, how do you know if it works?  I'd ask that for an interview.  I'd also ask why w.joinable() is tested before calling w.join().  Is there a circumstance in which w.joinable() will return false?
Think about further derivation
What would happen if a user derived from this class?  I'd recommend either declaring the destructor as virtual or declaring the class final to prevent derivation.
Be clear about what each mutex is locking
The name m_printLock suggests that the shared resource being protected is std::cout.  If we used std::basic_osyncstream as suggested in a comment, would you still need a mutex?  If so, what would it then be locking?  Generally, I like to have each mutex just lock one thing because it simplifies maintenance and clarifies the intent to other programmers.