STL container read thread-safety.

J

jason.cipriani

I know that the overall thread safety of STL containers is not
guaranteed. However, if I have an std::vector<int> or an
std::list<int>, and multiple threads are reading them but nothing is
writing them, do I still need to synchronize access to them? By
"reading" I mean iterating through with const_iterators, and also
copying them to other containers with the assignment operator.

What I mean is, am I guaranteed that, say, I don't know, obtaining a
const_iterator via std::list<int>::begin() isn't doing any internal
housekeeping or anything that would potentially make it not thread-
safe?

What about set and map?

Thanks,
Jason
 
E

Erik Wikström

I know that the overall thread safety of STL containers is not
guaranteed. However, if I have an std::vector<int> or an
std::list<int>, and multiple threads are reading them but nothing is
writing them, do I still need to synchronize access to them? By
"reading" I mean iterating through with const_iterators, and also
copying them to other containers with the assignment operator.

What I mean is, am I guaranteed that, say, I don't know, obtaining a
const_iterator via std::list<int>::begin() isn't doing any internal
housekeeping or anything that would potentially make it not thread-
safe?

What about set and map?

Reading should always be safe (unless you have a very weird library
implementation). However you might need a lock to ensure that no other
thread is writing at the same time as the first thread is reading, look
into readers-writer locks to solve this.
 
A

Abhishek Padmanabh

I know that the overall thread safety of STL containers is not
guaranteed. However, if I have an std::vector<int> or an
std::list<int>, and multiple threads are reading them but nothing is
writing them, do I still need to synchronize access to them? By
"reading" I mean iterating through with const_iterators, and also
copying them to other containers with the assignment operator.

For the copy (using assignment operator), the contention resource (if
it is being shared across threads) would become the conatiner to which
you are copying from the original list/vector/any other container. So,
you won't need synchronization for the original object but will need
it for the object it is being copied to.
What I mean is, am I guaranteed that, say, I don't know, obtaining a
const_iterator via std::list<int>::begin() isn't doing any internal
housekeeping or anything that would potentially make it not thread-
safe?

What about set and map?

The answer can probably be generalized across STL containers (depends
on STL implementation docs/guarantees as well). A usual mistake could
be modifying std::map with operator[]. It can be considered a bug in a
non-multithreaded app as well and might be a bit tough to catch in a
bigger codebase. So, that would be one point where I would be
cautious. Moreover, if there is a parallelized code section,
maintaining const-ness for the object that is just being read can be
useful to catch such errors. Just a thought.
 
J

Jim Langston

I know that the overall thread safety of STL containers is not
guaranteed. However, if I have an std::vector<int> or an
std::list<int>, and multiple threads are reading them but nothing is
writing them, do I still need to synchronize access to them? By
"reading" I mean iterating through with const_iterators, and also
copying them to other containers with the assignment operator.

What I mean is, am I guaranteed that, say, I don't know, obtaining a
const_iterator via std::list<int>::begin() isn't doing any internal
housekeeping or anything that would potentially make it not thread-
safe?

What about set and map?

If "nothing is writing them" is indeeed true, you *should* be okay most of
the time. However, how can you be 100% sure that something won't write to
it somewhere? Somehow you need to get the entries into the container for
your threads to read. If something is writing to a container while
something else is reading it, bad things happen.

It is much eaiser to wrap the container in a thread safe class then to make
sure your code doesn't write to a container when something is reading it.
 
J

James Kanze

I know that the overall thread safety of STL containers is not
guaranteed. However, if I have an std::vector<int> or an
std::list<int>, and multiple threads are reading them but
nothing is writing them, do I still need to synchronize access
to them?

What does your implementation say? I know that this is
supported by the STLport, the SGI implementations and to some
degree by g++, and I suspect that it is more or less universal,
but in the end, the standard doesn't say anything---yet---so all
you have are the guarantees of your implementation.
By "reading" I mean iterating through with const_iterators,
and also copying them to other containers with the assignment
operator.
What I mean is, am I guaranteed that, say, I don't know,
obtaining a const_iterator via std::list<int>::begin() isn't
doing any internal housekeeping or anything that would
potentially make it not thread- safe?
What about set and map?

The most wide spread convention is to extend the general Posix
rules to them, e.g. to make them obey the rules which apply to a
T[] under Posix. But as I said, the standard doesn't guarantee
it yet, so you'll have to check the documentation of your
implementation. (Good luck in finding it:).)
 
M

Michael.Boehnisch

I know that the overall thread safety of STL containers is not
guaranteed. However, if I have an std::vector<int> or an
std::list<int>, and multiple threads are reading them but nothing is
writing them, do I still need to synchronize access to them?

Iterators are self-contained and do not modify the sequence they
reference to. As long as you do not modify any shared data in your
concurrent threads, there is no need for synchronization. The
referenced container type does not matter, vector, list, set - applies
to all of them.
You need to be a little careful in regard to std::map - dereferencing
a non-existing element by [] operator actually creates it. You can use
this operator in threads only with synchronization mechanisms in
place, or you must be sure you are referencing existing elements only.
If you stick to iterators for traversal, no problem again.

best,

Michael
 
J

James Kanze

Iterators are self-contained and do not modify the sequence
they reference to.

Maybe. Copying an iterator can certainly modify data associated
with the container in the implementation I regularly use.
As long as you do not modify any shared data in your
concurrent threads, there is no need for synchronization.

As long as you conform to the requirements specified by your
implementation, there is no need for sychronization. At least
in the past, g++ has required synchronization even with
read-only accesses. (I'm not sure concerning the current
status; I think they have long term plans to move to the more
usual guarantees, but I'm not really sure of it.)
The referenced container type does not matter, vector, list,
set - applies to all of them.

Where do you read that?
You need to be a little careful in regard to std::map -
dereferencing a non-existing element by [] operator actually
creates it.

Which is modifying the container, anyway you look at it. Most
(but not all) implementations require external synchronization.
You can use this operator in threads only with synchronization
mechanisms in place, or you must be sure you are referencing
existing elements only.

Again, where did you read that?
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top