如何控制访问相同共享数据的两个线程的执行顺序



在我的示例中,线程1和2写入同一共享资源x。并且主线程将读取该值。我想得到结果24,即thread2然后thread1。

我该如何控制?我试图在1之前定义线程2,并在join之后打印两个线程的结果,结果是24,但由于线程以并行工作,因此不能保证这个结果

int x = 10;
void mainThread1(){
x *= 2; 
}
void mainThread2(){
x += 2;
}
int main() {
std::thread th1(mainThread1);
std::thread th2(mainThread2);
std::cout << x << std::endl; // random print 20 or 22
th1.join();
th2.join();
}

假设您正在寻找的不是这里的琐碎答案:在启动第二个线程之前加入第一个线程。您展示的是一个简化的示例,以说明更一般的情况。

由于线程在并行中工作,因此无法保证此结果

这是正确的。与多个线程之间的相对操作序列有关的问题;可见";在另一个执行线程中落入一个相当广泛、复杂和广泛的C++域,称为";"同步";。

线程间同步使用互斥、条件变量和原子。就像其他所有大型C++主题一样,在这里用Stackoverflow的简短回答来描述关于同步的所有需要描述的内容是不切实际的。这需要几页纸。因此,我只提供一个关于这个简单用例如何处理同步的胶囊摘要,并将所有进一步的血腥细节推荐给您最喜欢的C++教科书或参考资料,以获得更多信息。但如何做到这一点的基本概述是:

  1. 除了x之外,还定义一个互斥、一个条件变量和一个bool标志
  2. 第一个执行线程锁定互斥锁,更新x,设置bool标志,并通知条件变量,然后释放互斥锁
  3. 第二个执行线程锁定互斥锁,然后锁定条件变量wait_for,条件为flag == true
  4. 第二个执行线程更新x,并释放互斥

这是一个经典的解决方案,可以保证您所要查找的两个执行线程之间的执行顺序。以上回答了如何保证的结果

thread2然后thread1

在所示代码中生成。

您可以使用全局condition_variable,以便:

  • 要在第二个位置执行的线程等待它
  • 首先要执行的线程完成它的工作并设置它

请注意,由于虚假唤醒,线程可能会从对条件变量的等待中唤醒,因此您应该提供一个额外的机制,例如bool,以告知notify实际发生了。

【演示】

#include <condition_variable>
#include <iostream>
#include <mutex>
#include <thread>
int x{10};
bool ready{false};
std::mutex m{};
std::condition_variable cv{};
void mainThread1() {
std::unique_lock<std::mutex> lk{m};
cv.wait(lk, []{ return ready; });
x *= 2; 
}
void mainThread2() {
x += 2;
ready = true;
cv.notify_one();
}
int main() {
std::thread th1(mainThread1);
std::thread th2(mainThread2);
th1.join();
th2.join();
std::cout << x << "n";  // prints 24
}

一个更简单的解决方案是使用binary_semaphore。想法是一样的:线程1等待来自线程2的信号,但代码更高级、更精简。

【演示】

#include <iostream>
#include <semaphore>
#include <thread>
int x{10};
std::binary_semaphore bs{0};
void mainThread1() {
bs.acquire();
x *= 2; 
}
void mainThread2() {
x += 2;
bs.release();
}
int main() {
std::thread th1(mainThread1);
std::thread th2(mainThread2);
th1.join();
th2.join();
std::cout << x << "n";  // prints 24
}

最新更新