首页 > 解决方案 > 用不同的线程填充 std::vector

问题描述

我需要在不同的线程上填充一个 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();
    }
}

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

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

标签: c++stdstdvector

解决方案


相关问题:
默认情况下 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);

然后您可以显式添加该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;

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


推荐阅读