我可以使用 std::vector::swap 修改共享向量吗?

Can I use std::vector::swap to modify a shared vector?

我正在开发多个线程读取访问单个 std::vector 大量(和大)数据的软件。

我对多个 thead 访问单个对象的复杂性有一些基本的了解,使用互斥量可以大大简化事情。

就我而言,修改现有对象比复制它要昂贵得多。所以我正在考虑创建一个副本,修改副本(同时不持有互斥锁)和 然后将其交换回共享对象。

我不能使用 C++11,所以我无权访问移动操作,但据我了解 gcc 使用非常高效的 std::vector::swap() 可与移动操作相媲美(在速度方面)。

我在想这样的事情:

pthread_mutex_t mtx;

class bigdata_t { ... };
std::vector<bigdata_t> shared_vec; // accessed by multiple threads

void modify_bigdata()
{
    pthread_mutex_lock(&mtx);
    std::vector<bigdata_t> tmp_vec = shared_vec; // create copy
    pthread_mutex_unlock(&mtx);

    /*
     * Here, apply expensive modifications to tmp_vec
     */

    pthread_mutex_lock(&mtx);
    shared_vec.swap(tmp_vec); // this is very fast and does not copy data
    pthread_mutex_unlock(&mtx);
}

modify_bigdata() 仅由单个线程调用,因此这基本上是单个 writer/multiple reader 方法。

它运行得非常快,但是将数据交换回共享向量有点像作弊。

我的问题是:
这种方法是否正确且线程安全?

假设你交换了整个向量,如果任何 reader 线程在该向量中有引用是非常危险的,因为在交换时,另一个向量很可能被破坏,在这种情况下任何引用来自reader 线程可能会失效。

因此,每次您的 reader 线程访问向量时,它们都需要一个锁。所以使用 swap 在这里无济于事。它唯一可行的方法是通过使用某种多重 reader - 单个写入器锁来确保没有 reader 处于活动状态。

可能适合您的是

std::vector<std::shared_ptr<bigdata_t>> shared_vec;

这样,您只需正确同步指针交换并确保:

  • 一旦启动 reader 个线程或
  • ,向量的大小就不会改变
  • 您永远不会保留迭代器并且对 vector 的访问已正确同步。