C ++线程中未经共享的共享资源

时间:2015-05-07 11:47:04

标签: c++ multithreading mutex

想象一下以下场景:

#include <chrono>
#include <iostream>
#include <thread>
#include <vector>

void DoSomething(int* i)
{
    std::cout << *i << std::endl;
    std::this_thread::sleep_for(std::chrono::seconds(1));
    *i = 2;
    std::cout << *i << std::endl;
}

int main()
{
    std::vector<int> v = {0, 0, 0};
    v[0] = 1;
    std::this_thread::sleep_for(std::chrono::seconds(1));
    std::thread t(&DoSomething, &v[0]);
    t.join();
    std::cout << v[0] << std::endl;
}

是否有任何理由应该与向量元素一起传递互斥锁?

Pd积。从2015年5月8日起

在发帖时我没有详细说明这个问题,因为我不想影响答案。你昨天回答的问题几乎是我的理解。但是,有人向我建议,直觉行为在线程场景中可能无法像人们希望的那样可用。特别地,在这种情况下,已经建议,例如,假设在主线程上发生的写入v [0] = 1是在没有互斥的情况下将在不能保证在DoSomething中打印时反映的事物。作为一种可能的解释,我被提出值可能会进入线程可访问的内存,但是在将其写入跨线程内存之前,它可能会被另一个线程的状态换出,并且再次证明它是唯一的保证方式期望的传播将使用互斥锁。你对这个论点有什么看法?

2 个答案:

答案 0 :(得分:4)

互斥锁用于同步多个线程之间的数据访问。如果两个或多个线程访问相同的数据,并且其中至少有一个是编写器,则需要进行同步。

在您的情况下,DoSomething会写入您传递给它的元素。但是,在当前示例中,执行写入的线程是此时访问元素的 only 线程,因为主线程在以下连接中立即被阻止。

但是,如果主线程同时访问v,则需要保护该访问权限:

// BROKEN CODE BELOW

int main()
{
    std::vector<int> v = {0, 0, 0};
    std::thread t(&DoSomething, &v[0]);
    // swapped the join and the cout; now cout accesses v[0] 
    // while DoSomething writes to it, which is bad;
    std::cout << v[0] << std::endl;
    t.join();
}

至于您的编辑:您基本上担心v[0]的初始分配可能会重新排序,因此DoSomething线程无法看到它。原则上,写入可以以并发线程将观察到的不同值的方式重新排序,而不是直观地预期。防止这种情况的唯一方法是插入明确强制执行某个排序的memory barriers。在C ++中,这通常通过线程同步原语(如std::mutex或atomics。

)发生

幸运的是,the creation of a thread acts as such a memory barrier。因此,在您的示例中,在创建线程之前发生对v的初始写入,一切都很好,您将不会遇到任何有害的重新排序。

答案 1 :(得分:3)

没有。事实上,线程创建+立即连接使这成为一个有效(非常昂贵)的顺序函数调用。