Tootsie
Tootsie

Reputation: 909

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

I'm working on software where multiple threads read-access a single std::vector with a lot (and large) data.

I have some basic understanding of the complexities of multiple theads accessing a single object and things can be greatly simplified by using a mutex.

In my case, modifying an existing object is a lot more expensive that copying it. So I was thinking about creating a copy, modifing the copy (while not holding the mutex) and then swapping it back into the shared object.

I cannot use C++11, so I don't have access to move operations, but it is my understanding that gcc uses a very efficient std::vector::swap() that is comparable with move operations (in terms of speed).

I was thinking about something like this:

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() is only called by a single thread, so this is basically a single writer/multiple reader approach.

It runs very fast, but swapping data back into the shared vector kind of feels like cheating.

My question is:
Is this approach correct and thread-safe ?

Upvotes: 0

Views: 1159

Answers (1)

Phil1970
Phil1970

Reputation: 2624

Assuming that you swap the whole vector, it is very dangerous if any reader thread has reference inside that vector as when swapping, it is very possible that the other vector get destroyed in which case any reference from reader threads can become invalide.

So every time your reader thread would access the vector, they would need a lock. So using swap won't help here. The only way it could works is that by ensuring that no reader are active by using some kind of multiple reader - single writer lock.

What might works for you is

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

That way, you only need to properly synchronize the exchange of pointers and ensure that either:

  • the size of the vector does not change once you have started reader threads or
  • that you never keep iterator around and access to vector is properly synchronized.

Upvotes: 1

Related Questions