Concurrency/Multithreading: 是否可以通过这种方式生成相同的输出?

Concurrency/Multithreading: Is it possible to generate the same output this way?

一个线程应该向上计数,另一个向下计数。输出各不相同,但它通常能够很好地打印 countUp() 部分,然后在 countDown() 部分中出现一些缺陷。最初,我确定问题出在两个线程都在争夺 cout 资源。我认为这可以通过 shared_print() 和互斥体来解决。但是,输出仍然会有所不同,坦率地说,我并没有全神贯注于这个 concurrency/multithreading 东西。我的主要问题是,是否有可能生成相同的输出,或者它总是会以某种方式变化吗?提前致谢。

mutex mu;
int counter= 0;

int main()
{
   
    thread t1(countUp);     //t1 starts running
    thread t2(countDown);   //t2 starts running
    t1.join();
    t2.join();
}

//Counts up from 0 to 20
void countUp()
{
    while(counter < 20)
    {
        counter++;
        shared_print(string("Counting Up: "), counter);
        //counter++;
    }
}

//Counts down from 20 to 0
void countDown()
{
   
   while(counter > 0)
   {
       
       //counter--;
       shared_print(string("Counting Down: "), counter);
       counter--;
   }
}

//Prints both of the counts
void shared_print(string description, int number)
{
    lock_guard<std::mutex> guard(mu);
    //mu.lock();
    cout << description << number << endl;
    //mu.unlock();
}

输出与此不同:

Counting Up: 1
Counting Up: 2
Counting Up: 3
Counting Up: 4
      .
      .
      .
Counting Up: 20

对此(注意在倒计时开始时用 1 代替 20):

Counting Up: 1
Counting Up: 2
Counting Up: 3
Counting Up: 4
Counting Up: 5
Counting Up: 6
Counting Up: 7
Counting Up: 8
Counting Up: 9
Counting Up: 10
Counting Up: 11
Counting Up: 12
Counting Up: 13
Counting Up: 14
Counting Up: 15
Counting Up: 16
Counting Up: 17
Counting Up: 18
Counting Up: 19
Counting Up: 20
Counting Down: 1
Counting Down: 19
Counting Down: 18
Counting Down: 17
Counting Down: 16
Counting Down: 15
Counting Down: 14
Counting Down: 13
Counting Down: 12
Counting Down: 11
Counting Down: 10
Counting Down: 9
Counting Down: 8
Counting Down: 7
Counting Down: 6
Counting Down: 5
Counting Down: 4
Counting Down: 3
Counting Down: 2
Counting Down: 1

使用条件变量等待,等待操作自动释放互斥量。

     mutex mu;
        atomic<int> counter = 0;
        condition_variable m_cvO;
        
       //Counts up from 0 to 20
void countUp()
{
    unique_lock<mutex> lck(mu);
    m_cvO.wait(lck, [&]() {
        return counter < 20;
        });
    while (counter < 20)
    {
        counter++;
        shared_print(string("Counting Up: "), counter);
        //counter++;
    }
    m_cvO.notify_all();
   
}
    
       //Counts down from 20 to 0
    void countDown()
    {
        unique_lock<mutex> lck(mu);
        m_cvO.wait(lck, [&]() {
            return counter > 0;
            });
        while (counter > 0)
        {
    
            //counter--;
            shared_print(string("Counting Down: "), counter);
            counter--;
        }
        m_cvO.notify_all();
       
    }
    
    //Prints both of the counts
    void shared_print(string description, int number)
    {
      
        //mu.lock();
        cout << description << number << endl;
        //mu.unlock();
    }