用不同的线程填充 std::vector

dzu*_*ukp 1 c++ std stdvector

我需要在不同的线程上填充一个 std::vector。

它是正确的代码吗?或者我应该为我的代码添加互斥锁?

void func(int i, std::vector<float>& vec)
{
    vec[i] = i;
}

int main()
{
    std::vector<float> vec(6);
    std::list<std::thread> threads;
    for (int i = 0; i < 6; i++)
    {
        threads.push_back(std::thread(func, i, std::ref(vec)));
    }
    for (auto iter = threads.begin(); iter != threads.end(); iter++)
    {
      (*iter).join();
    }
}
Run Code Online (Sandbox Code Playgroud)

我测试了我的代码它工作正常。有什么陷阱吗?它是线程安全的代码吗?

如何通过不同的线程获取 std::vector 数据?

Joh*_*eau 7

相关问题:
默认情况下 std::vector 线程安全和并发吗?为什么或者为什么不?.

它是线程安全的,因为您没有修改向量大小,也没有尝试在不同线程中写入相同的内存位置。

为了将来为没有深入链接的人证明这个答案:

  1. 它不是线程安全不仅是因为他们使用的[]运营商。它是线程安全的,因为每个线程都显式地修改内存中的不同位置。

  2. 如果所有线程只使用 读取相同的位置[],那将是线程安全的。

  3. 如果所有线程都写入相同的位置,使用[]不会阻止它们相互干扰。

  4. 我认为如果这是生产代码,至少需要一条评论来描述为什么这是线程安全的。不确定是否有任何编译时方法来防止有人在修改此函数时射中自己的脚。


在第 4 点,我们希望与此代码的未来用户交流:

  1. 不,我们不会保护这个标准库容器,即使这应该是你的本能反应,而且
  2. 是的,我们已经对其进行了分析,它是安全的。

最简单的方法是在那里发表评论,但有一句谚语:

编译器不会读取注释,我也不会。-
Bjarne Stroustrup

我认为某种[[attributes]]应该是做到这一点的方式?尽管内置程序似乎不支持任何类型的线程安全检查。


Clang 似乎提供了线程安全分析

该分析仍在积极开发中,但它已经足够成熟,可以在工业环境中部署。

假设您实现了其他需要 astd::mutex负责您的功能std::vector

std::mutex _mu;
std::vector<int> _vec GUARDED_BY(_mu);
Run Code Online (Sandbox Code Playgroud)

那么您可以显式添加NO_THREAD_SAFETY_ANALYSIS属性以关闭针对这一特定功能的安全检查。我认为最好将此与评论结合起来:

// I know this doesn't look safe but it is as long as
// the caller always launches it with different values of `i`
void foo(int i, std::vector<int>& vec) NO_THREAD_SAFETY_ANALYSIS;
Run Code Online (Sandbox Code Playgroud)

的使用GUARDED_BY告诉我,将来您正在考虑线程安全。的使用NO_THREAD_SAFETY_ANALYSIS表明您已确定此功能可以使用 - 特别是当其他修改您的功能vector未标记时NO_THREAD_SAFETY_ANALYSIS