Im new to using STL vectors and saw the below description on MSDN...
Does this mean that if I have two different objects of an STL vector, I cannot read from the first on Thread1, at the same time as writing to the second on Thread2?
MSDN says:
When /MT, /MTd, /MD, or /MDd is used, the following thread-safety rules are in effect:
Container Classes (vector, deque, list, queue, stack , priority_queue, valarray, map, multimap, set, multiset, basic_string, bitset) and complex
For reads to the same object, the object is thread safe for reading:
From one thread at a time when no writers on other threads.
From many threads at a time when no writers on other threads.
For writes to the same object, the object is thread safe for writing from one thread when no readers on other threads
For reads to different objects of the same class, the object is thread safe for reading:
From one thread at a time.
From one thread at a time when no writers on other threads.
From many threads at a time.
From many threads at a time when no writers on other threads.
For writes to different objects of the same class, the object is thread safe for writing:
From one thread when no readers on other threads.
From many threads
JVene
July 3rd, 2007, 11:08 AM
These definitions would apply just as well to an integer.
I would call it 'not' threadsafe, but I suppose that depends on one's definition.
For example, it's safe to read from an integer if you know there's no other thread that can possibly change it. That's not exactly a definition of safe, and it means the integer isn't protected by any critical section or mutex.
It's possible, though not recommendable, to construct code to 'behave' in this regard. That is, controlling the sequence of events so that once a value is written or a container is modified there can only be reads until some other condition is met, which guarantees that all reading threads are stopped until the value or container is modified, all managed without critical sections or mutexes. There are also 'lock free' concepts, which work something along these lines, and can be of some value in specific situations.
Generally, however, you use critical sections or mutexes to 'guard' access to memory that might be accessed from multiple threads, and you do that for all accesses, reading or writing. This has a minor performance penalty (less with critical sections), so you apply it with some care, but the penalty is fairly small, so only the most performance critical code needs finesse.
Most implementations of STL (all that I've seen) are not threadsafe in the sense that you can proceed to code with writes/reads at will without using critical sections or mutexes yourself. Only you can determine if individual values can be read with reasonable safety without locking (while, obviously, locking any writes) - there are situations where a time oriented delay or offset in the reading of a value under change by another thread is acceptable, and many occasions where it's not - your judgment is required there. It's most likely that such a design applies to primitives. Containers and character arrays have more complex behavior (that of a group that should be viewed as a whole whereas a writing thread on a container can put the container in an irrational state while it's being modified). This applies to strings, vectors, lists, trees, etc.
As such, for containers, the general rule is to lock the entire container (or string) for read and write accesses.
If you find yourself concerned about repeated lock/unlock cycles, a classic symptom in C++ design that an object is implied, you can consider 'owning' an STL container in another object that always locks/unlocks for every access. That makes it 'always' threadsafe.
miteshpandey
July 3rd, 2007, 11:32 AM
These definitions would apply just as well to an integer.
At first I thought just like you. :)
But I think it should be differentiated what STL functions (member functions or free functions) constitute reads and writes.
I agree the general view that STL is not thread-safe.
Paul McKenzie
July 4th, 2007, 11:40 AM
Im new to using STL vectors and saw the below description on MSDN...
Does this mean that if I have two different objects of an STL vector, I cannot read from the first on Thread1, at the same time as writing to the second on Thread2?There is no requirement for anything of C++ to be thread safe. Thread safety is not mentioned at all in the current ANSI standard.
So assume nothing from standard C++, including STL, iostreams, etc. is thread-safe.
Regards,
Paul McKenzie
ViewDoc
July 6th, 2007, 06:46 AM
To :jvene
This is a excellent explanation....
i understood the concept of implied object.that actually guards access to container. i have also seen an article by "Arjay" on this concept.But i am still confused that two objects of Vector class that are in the different Thread are safe. i mean if i have a two class having two Vector objects .. and if i guard access in the one class through one of synchronization techniques.. then what about the other vector object in the other class. Ok I may use same synchronization object in the both class to guard access. But in case if I have two different synchronization for different classes. Will that be safe
Regards
view
JVene
July 6th, 2007, 10:28 AM
If you are able to guarantee, by design, that you have two vectors, and each vector is acted upon by a different thread, with no potential for two threads accessing the same vector, then the code can run without any other synchronization efforts just as if each were in a single threaded application.
This is true for any variables, be they primitives, objects or containers from any library, as long as there is absolutely nothing static or common in the containers (which is typical, but certainly not guaranteed).
A classic case of a problem in this regard is localtime from the C library. It would seem that localtime is just a function, and that calling that function from two threads simultaneously would be of no issue. However, localtime uses a static structure in which to deposit the time information, which means that a subsequent call to localtime changes the values in that structure on each call. This happens even if two calls are made to localtime within a single thread, whilst the code assumes the two return values are different. They are not, and the second call overwrites the values left behind by the first call. So, too, there will be an overwrite if multiple threads use localtime.
Any object could be constructed in such a way that some similarly static internal structure is used, and if so, that object will be inherently unsafe for threading without protection, and even more than just protection, without copying the result to a private variable known to be independent. Like localtime, even if protected for the call to localtime, since its internal structure is a static value, its contents will not remain stable once a lock upon it is released.
Conversely, for most well designed objects and containers, one can expect the object is designed to fully encapsulate internal values such that nothing is shared between instances. If that is true, then multiple instances will not interfere with each other. This would be true of multiple containers instantiated for the same type. That is, if two vectors are created to contain some object, even though both containers hold the same type of object, the containers are independent. As such, they need NOT be synchronized against each other. If there is any chance that two threads might attempt to act upon the same container, synchronization is required. This assumes the containers themselves are designed to operate independently.
There is an infamous exception to this assumption in Visual Studio 6 std::string class, for which there's a knowledge base article. Memory corruption (in the form of double deletes) can occur in threaded use of that class, but I've not found the same problem in more recent Visual Studio implementations of the STL. The VS6 version of std::string is, therefore, inherently not safe for threaded work.
From a standard practice viewpoint, however, it is not commonly practicable to guarantee that there will never be a future development extension that might violate the rule that a container is acted upon by only one thread at a time. At one point in the development it may be possible to make such an assertion, but in future extensions it may happen that a feature is added that does spin off a thread which needs access to a container previously assumed to be 'owned' by a thread, which introduces a synchronization problem previously assumed to be designed out of the specification.
If an object represents a thread, you can compartmentalize operations using that object to ensure that a thread 'owns' it's objects, obviating the potential for two threads acting upon a common variable or container. On the other hand, if a thread acts upon objects owned by something NOT representing that thread (say, representing a window that has spun off threads), even if you adhere to a thread ownership implementation, you have nothing else that implies that ownership, and so leave open the possibility that yet another thread might gain access to some common variable, creating a contention problem.
As such, on any occasion that you have threads acting upon variables owned by something else, as in a window that owns containers upon which threads may act (including the UI thread), you should generally assume that requires synchronization. To stop that requirement (working in a 'lock free' fashion), you should try to 'hand off' ownership of such elements.
In my own work, I may use a smart pointer to 'own' a container. If I want to 'hand over' that container to a thread, I can detach the container from the 'window' that once owned it, give it to the thread, leaving nothing for some OTHER thread to use that could create a contention for the container. While there are times this is appropriate, there are simply situations where this doesn't make sense. Only you can determine which is plausible.
Given the example of the std::string class in Visual Studio 6, which I would have expected to work well in threaded work (that is, two independent strings in two different threads shouldn't have anything to do with each other), it appears that this was never the case for that version of the STL. As such, I'm not sure how we can guarantee the STL is safe in this regard generally - we can only assess a particular implementation of the STL as issued for our compiler.
This implies that for portability over different versions of the STL on different compilers, one must be careful about assumptions regarding the full isolation of different instances of STL containers and objects. Certainly this was not true of Visual Studio 6's std::string class, which is the last thing I would have expected. Unless there is a stated guarantee to the contrary, assumption is likely to generate an unexpected bug in future releases.
With respect to a string class, however, I find the notion of the std::string bug rather disconcerting. I see no good reason for the problem to have ever occurred (in that the design should have been better). I posit that it should be reasonable to assume that two strings, entirely independent instances, should have nothing whatsoever to do with each other, such that I can freely use them in various objects and containers in threaded development. I would personally insist on knowing that the string class I'm using has no problem with that practice in whatever compiler I move to. I would like that to be true, also, of the various containers, but I can more easily accept that kind of 'collision' in something less common than a string.
I don't recall ever having a problem with CString, when I once used that in Visual Studio versions prior to and including 6, but I long ago abandoned MFC, and therefore that implementation of CString, in favor of cross platform frameworks which have their own strings devoid of that problem.
ViewDoc
July 9th, 2007, 12:12 AM
Jvene:
i am very thankfull to you. you must have must have spent very much time to write this nice article.. this is really great. now i am clear. i had read the std::sting article. but i was not clear. thanks for this time dear. you are very nice guy.
regards
view
JVene
July 9th, 2007, 11:37 AM
I'm going to need some new caps because you're making my head swell :)
Thanks.
In an effort to avoid taking more credit than is due, though, I should say it didn't take all that much time. I type over 100 wpm, and on material I know well I can spin out a stream of thought almost as quickly as just saying it to someone. I think a few times I've been too verbose, and I don't catch my typos when I do that - I just hope people can read "the" instead of "that" or some other such misstep.
Glad it helped!
Arjay
July 9th, 2007, 12:43 PM
JVene, you alway have good stuff. Thanks as well. :)
codeguru.com
Copyright Internet.com Inc., All Rights Reserved.