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 μ
}
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”。
我有以下代码
#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 μ
}
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”。