我想使std::string append函数线程安全,因为我正在附加来自不同线程的特定字符串。
我是 c++ 的初学者,所以我不确定这可能会导致什么问题。
我正在考虑的解决方案是不使用somestring.append("appendthis");
使用以下代码:
bool appendtsReady = true;
void appendts(std::string& originalString, char* app)
{
while (!appendtsReady) {}
appendtsReady = false;
originalString.append(app);
appendtsReady = true;
}
appendts(somestring, "appendthis");
我希望如果字符串被附加新请求 appendts(somestring, "appendthis_from_different_thread");
将被循环捕获,直到上一个追加完成。
这个解决方案是不是太幼稚了?
这不是线程安全的方法。即使appendtsReady
是一个原子布尔值(如果你不改变逻辑)!原因如下:
考虑没有人写入布尔值并且两个线程执行appendts
。两人都读了布尔值。现在两个都能读真吗?是的!因为在 while 循环中读取appendtsReady
和下面一行的写入之间有一个微小的延迟!如此之小,它几乎总是可以工作,但是第二个线程的读取可能恰好在延迟期间发生,因此两者都读取true
。
解决方案:让他们分享一个std::mutex
。
std::mutex mutex;
void appendts(std::string& originalString, char* app)
{
std::lock_guard<std::mutex> lock(mutex);
originalString.append(app);
}
现在,您可以从两个线程调用此方法,前提是两个线程都知道相同的互斥锁。要么全局声明它(不太好),要么将互斥锁的引用传递给两个线程。
std::mutex
通过锁定和解锁来工作,就像你想要的布尔变量一样。但是,std::mutex
具有线程安全性。
我建议使用std::lock_guard
而不是mutex.lock(); work(); mutex.unlock();
因为它提供了 RAII 的好处,也就是说,如果work()
返回、投掷或中断或其他什么,互斥锁会自动解锁。