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

Filling std::vector by different threads

我需要在不同的线程上填写一个 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 数据?

相关问题:
.

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

为未深入研究 link 的任何人提供此答案的未来证明:

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

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

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

  4. 我认为如果这是生产代码,至少需要一条说明为什么这是线程安全的注释。不确定是否有任何编译时方法可以防止有人在修改此函数时搬起石头砸自己的脚。


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

  1. 不,我们不会保护这个标准库容器,尽管这应该是您的直觉反应,并且
  2. 是的,我们已经对其进行了分析,它是安全的。

最简单的方法就是在里面贴个评论,不过有句话说:

The compiler doesn't read comments and neither do I.
-Bjarne Stroustrup

我认为某种 [[attributes]] 应该是执行此操作的方法?尽管 built-ins 似乎不支持任何类型的线程安全检查。


Clang 似乎提供 Thread Safety Analysis:

The analysis is still under active development, but it is mature enough to be deployed in an industrial setting.

假设您实现其他功能需要 std::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.

是它是线程安全的,因为您既不会从不同的线程写入向量对象本身,也不会写入向量底层数组中的同一对象。

构建向量时,您为 6 个元素分配 space,并为 int 等 pod 类型用零填充它们。这些元素放置在一个由 vector 拥有和管理的数组中,vector 通过迭代器和 operator [].

公开它们

因此,当您编辑向量中的元素时,您不会编辑向量本身,因此您不必使用互斥锁来保护向量。

如果要修改向量本身或不同线程中的相同元素,则需要互斥体。