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

时间:2018-10-01 22:43:34

标签: c++ multithreading c++98

我正在开发一个软件,其中多个线程读取访问具有大量数据(大数据)的单个<collection xmlns="http://exist-db.org/collection-config/1.0"> <triggers> <trigger class="org.exist.jms.replication.publish.ReplicationTrigger"> <!-- Class name of the initial context provider, default value for ActiveMQ see javax.naming.Context#INITIAL_CONTEXT_FACTORY --> <parameter name="java.naming.factory.initial" value="org.apache.activemq.jndi.ActiveMQInitialContextFactory"/> <!-- URL of the message broker, default value for ActiveMQ see javax.naming.Context#PROVIDER_URL --> <parameter name="java.naming.provider.url" value="tcp://localhost:61616"/> <!-- Lookup connection factory see javax.naming.InitialContext#lookup(String) --> <parameter name="connection-factory" value="ConnectionFactory"/> <!-- Lookup destination (topic) see javax.naming.InitialContext#lookup(String) --> <parameter name="destination" value="dynamicTopics/eXistdb-replication-example"/> </trigger> <trigger event="update" class="org.exist.collections.triggers.XQueryTrigger"> <parameter name="url" value="xmldb:exist:///db/triggerUpdate.xql"/> </trigger> </triggers> </collection>

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

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

我无法使用C ++ 11,因此我无权进行移动操作,但是据我了解,std::vector使用了非常有效的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); } 仅由单个线程调用,因此,这基本上是单个编写器/多个读取器的方法。

它运行速度非常快,但是将数据交换回共享矢量中的感觉就像作弊。

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

1 个答案:

答案 0 :(得分:1)

假设您交换了整个向量,那么当任何读取器线程在该向量中具有引用时,就像在交换时那样,这是非常危险的,另一个向量很可能被破坏,在这种情况下,来自读取器线程的任何引用都可能变为无效。

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

最适合您的是

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

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

  • 启动阅读器线程或
  • 后,向量的大小不会更改
  • 您永远不会保留迭代器,并且可以正确同步访问vector。