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

C++ 我可以使用std::vector::swap修改共享向量吗?,c++,multithreading,c++98,C++,Multithreading,C++98,我正在开发一个软件,在这个软件中,多个线程通过大量(和大量)数据读取访问单个std::vector 我对多个Thead访问单个对象的复杂性有一些基本的了解,使用互斥可以大大简化事情 在我的例子中,修改现有对象比复制它要昂贵得多。所以我考虑创建一个副本,修改副本(同时不持有互斥)并 然后将其交换回共享对象 我不能使用C++11,因此我无法访问移动操作,但据我所知,gcc使用了一种非常有效的std::vector::swap(),与移动操作(速度)相当 我在想这样的事情: pthread_mutex

我正在开发一个软件,在这个软件中,多个线程通过大量(和大量)数据读取访问单个
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);
}
pthread\u mutex\u t mtx;
类bigdata_t{…};
std::vector shared_vec;//由多个线程访问
void modify_bigdata()
{
pthread_mutex_lock(&mtx);
std::vector tmp_vec=shared_vec;//创建副本
pthread_mutex_unlock(&mtx);
/*
*这里,将昂贵的修改应用于tmp_vec
*/
pthread_mutex_lock(&mtx);
shared_vec.swap(tmp_vec);//这非常快,并且不会复制数据
pthread_mutex_unlock(&mtx);
}
modify\u bigdata()

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

我的问题是:

这种方法正确且线程安全吗?

假设您交换整个向量,如果任何读卡器线程在该向量内有引用,这是非常危险的,因为在交换时,另一个向量很可能被破坏,在这种情况下,来自读卡器线程的任何引用都可能失效

所以每次你的读线程访问向量时,他们都需要一个锁。所以使用swap在这里没有帮助。唯一可行的方法是通过使用某种多读-单写锁定来确保没有读卡器处于活动状态

对你有用的是

std::vector<std::shared_ptr<bigdata_t>> shared_vec;
std::vector shared\u vec;
这样,您只需正确同步指针的交换,并确保:

  • 一旦启动读取器线程或
  • 您永远不会保持迭代器的存在,并且对向量的访问是正确同步的

你没有给
bigdata\u t
它自己的
swap
成员吗?如果两个线程调用modify\u bigdata(),每个线程都创建一个副本并同时修改它们的副本,那么一个线程可以交换,另一个线程可以立即取消其中一个线程的修改。您肯定希望保留所有线程的所有修改,因此必须锁定、修改、解锁和放弃复制和交换以及内部解锁()和锁定(),只要没有对
modify\u bigdata
的并发调用,这应该可以工作。我看不出调用一个满足您要求的函数有什么不忠之处。请注意,如果
向量
副本引发异常,您的互斥锁将保持锁定状态。例如,通过为互斥体使用RAII包装可以避免这种情况,Boost有一个
作用域锁定
来实现这一点。你应该在你的问题中说,只有一个编写器,所有其他线程都是读卡器——在这种情况下,正如@Praetorian所说,“修改现有对象比复制它要昂贵得多。”-但是你可以复制、修改和交换。。。既然您最终修改了一个副本,那么这怎么比一次修改更有效呢?如果这是因为锁定,那么您的问题的措词就不正确了……关于潜在悬挂引用的观点很有道理。这不适用于我的具体情况,但我在问题中没有提到这一点。