C++ Set:线程1正在插入,插入结果对线程2的迭代器是否可见?

C++ Set: thread 1 is inserting, is the inserting result visible to iterator in thread 2?

我有以下代码

#include <thread>
#include <mutex>
#include <condition_variable>
#include <iostream>
#include <set>
#include <string>
#include <chrono>
#include <atomic>
using namespace std;

set<string> messages_;
mutex mu;


void thread1() {
  for(int i=0; i<20; ++i) {
    {
      lock_guard<mutex> lock(mu);
      messages_.insert(to_string(i));
    }
    this_thread::sleep_for(chrono::milliseconds(20));
  }
}


condition_variable cond;
mutex mutex_;
atomic<bool> stop{false};
int workaround = 0;

mutex* GetCoutMutex() {
  static std::mutex mu;
  return &mu;
}

void Work() {
  workaround++;
  unique_lock<mutex> lock(mu);
  for(auto it=messages_.begin(); it!=messages_.end(); ) {
    lock.unlock();
    {
      lock_guard<mutex> cout_lock(*GetCoutMutex());
      cout << "work around: " << workaround << ", message: " << *it << endl;
    }
    lock.lock();
    it=messages_.erase(it);
  }
}

void thread2() {
  while(!stop.load(memory_order_acquire)) {
    Work();
    unique_lock<mutex> lock(mutex_);
    cond.wait_for(lock, chrono::milliseconds(50), []{ return stop.load(memory_order_acquire); });
  }
}


int main() {
  thread t1(thread1), t2(thread2);
  t1.join();
  this_thread::sleep_for(chrono::milliseconds(100));
  stop.store(true, memory_order_release);
  cond.notify_one();
  t2.join();
}

我的预期输出是

work around: 1, message: 0
work around: 2, message: 1
work around: 2, message: 2
work around: 3, message: 3
work around: 3, message: 4
work around: 4, message: 5
work around: 4, message: 6
work around: 4, message: 7
work around: 5, message: 8
work around: 5, message: 9
work around: 6, message: 10
work around: 6, message: 11
work around: 7, message: 12
work around: 7, message: 13
work around: 7, message: 14
work around: 8, message: 15
work around: 8, message: 16
work around: 9, message: 17
work around: 9, message: 18
work around: 9, message: 19

其中,消息编号为递增序列0,1,2,...,19,大部分执行符合预期。 但是,我在某些执行中得到了以下输出:

work around: 1, message: 0
work around: 2, message: 1
work around: 2, message: 2
work around: 3, message: 3
work around: 3, message: 4
work around: 4, message: 5
work around: 4, message: 6
work around: 5, message: 7
work around: 5, message: 8
work around: 6, message: 10
work around: 6, message: 11
work around: 6, message: 9
work around: 7, message: 12
work around: 7, message: 13
work around: 8, message: 14
work around: 8, message: 15
work around: 9, message: 16
work around: 9, message: 17
work around: 9, message: 18
work around: 10, message: 19

据我所知,thread1和thread2是同步的mu,所以thread1的插入应该对thread2可见。由于thread1在10之前插入9,而thread2在顺序迭代set,所以thread2应该先输出9。

我很困惑。有人可以解释为什么 10 在 9 之前输出吗?

由于集合包含std::string,元素按字典顺序排序。

假设线程 1 在线程 2 等待 condvar 时插入字符串“9”、“10”和“11”。在这种情况下,“10”将是最小的字符串,因此它将首先打印,然后是“11”和“9”。