5

I have unexpected assertions faillures in my code using a checked STL implentation.

After some research, I narrowed down the problem to a push_back in a vector called from a different thread than the one in which the vector was created.

The simplest code to reproduce this problem is :

class SomeClass
    {
    private:
        std::vector<int> theVector;
    public:
        SomeClass () 
        {
            theVector.push_back(1); // Ok
        }


        void add()
     {
          theVector.push_back(1); // Crash 
     }
};

The only difference is that SomeClass is instanciated from my main thread, and add is called from another thread. However, there is no concurency issue : in the simplest form of code I used for troubleshooting nobody is reading or writing from this vector except the cases I mentioned above.

Tracing into the push_back code, I noticed that some methods from std::vector like count() or size() return garbage, when it's called from the other thred (method "add"), and correct values when called from the creating thread (in the constructor for example)

Should I conclude that std::vector is not usable in a multithreaded environement ? Or is there a solution for this problem ?

EDIT : removed volatile

EDIT 2 : Do you think it's possible that the problem doesn't lie in multithread ? In my test run, add is called only once (verified using a break point). If I remove the push_back from the constructor, I still crashes. So in the end, even with only one call to a vector's method, in a function called once make the assertion fail. Therefore there can't be concurency, or ... ?

Dinaiz
  • 2,213
  • 4
  • 22
  • 32
  • 2
    if there's indeed no concurrency vector should work. If there're 2 or more threads working with vector *in parallel*, this will not work. – Drakosha Dec 10 '10 at 15:02
  • 1
    Are you in an environment where each thread has its own heap? – JimR Dec 10 '10 at 15:07
  • -1: Your code can't even compile since `push_back()` is not declared as `volatile'. Can you provide a more detailed code/description? – Yakov Galka Dec 10 '10 at 15:21
  • 2
    "Should I conclude that std::vector is not usable in a multithreaded environement ?" -- not at all, vector is not supposed to do any different in multi threaded application than it does in single threaded. In fact if you compare C++0x (which is thread-aware) vector isn't any different from C++97 (which isn't thread-aware). It's the responsibility of the application, and not the vector, to provide serialization where necessary. In your case I think your assertion that multi-threading has no role in observable behavior is likely to be false, do the proper locking instead of speculating. – Gene Bushuyev Dec 10 '10 at 15:24
  • @JimR - and what would that be? Threads always share the same free store, which is thread-safe, it's the Standard requirement. – Gene Bushuyev Dec 10 '10 at 15:25
  • @Gene: I *think* in OS/2 there were separate thread heaps. If the push_back involved a free/delete and then another new/malloc things would crash. This was pre STL with the Rogue Wave libraries that were thread-safe. And no, every environment does not always share the same free store across threads. – JimR Dec 10 '10 at 15:57
  • @JimR - I don't think there a person alive who remembers OS/2 architecture (and it's irrelevant nowadays anyway), but they wouldn't be threads anymore if they didn't share the free store. In any case threads are pretty clearly defined by Posix, Windows, and C++0x, so there is no reason to speculate about the impossible. – Gene Bushuyev Dec 10 '10 at 16:10
  • @Gene: Evidently there's at least one that remembers something of OS/2 (me) and I was simply asking a question to clarify. Note that the successor to OS/2, ECommStation is still in use in banks. Who are _you_ to say the questioner isn't working for a bank using OS/2? You come across as combative and ill informed. – JimR Dec 10 '10 at 16:15
  • The Object is declare globally or in the main function ?. – Luis G. Costantini R. Dec 10 '10 at 16:24

4 Answers4

8

std::vector definitely is usable in a multi-threaded environment, provided you don't access the vector from two threads at once. I do it all the time without trouble.

Since vector isn't the problem, you need to look more closely at your synchronization mechanism, as this is most likely the problem.

I noticed that you marked the vector as volatile. Do you expect that making it volatile will provide synchronization? Because it won't. See here for more information.

EDIT: Originally provided wrong link. This is now fixed. Sorry for confusion.

Community
  • 1
  • 1
John Dibling
  • 99,718
  • 31
  • 186
  • 324
2

If you can guarantee that nobody is writing to or reading from the vector when you call push_back, there's no reason that it should fail. You could be dealing with higher-level memory corruption. You should verify that "this" points to a genuine instance of SomeClass, check it's other members, etc.

Puppy
  • 144,682
  • 38
  • 256
  • 465
  • You guys are indeed right : the problem wasn't the vactor or the threads but the SomeClass instance. Thanks a lot for your ideas – Dinaiz Dec 10 '10 at 17:05
1

Whether Standard Library supports multithreading is implementation defined. You have to read documentation for your specific compiler.

Additionaly what you can do is to add some log messages as in the following code:

class SomeClass
    {
    private:
        volatile std::vector<int> theVector;
    public:
        SomeClass () 
        {
            std::cout << "SomeClass::SomeClass" << std::endl;
            theVector.push_back(1); // Ok
        }
        ~SomeClass ()
        {
            std::cout << "SomeClass::~SomeClass" << std::endl;
        }
        void add()
        {
            std::cout << "SomeClass::add" << std::endl;
            theVector.push_back(1);
        }
};

Make sure that instance of the SomeClass is still exists when you call add function.

Kirill V. Lyadvinsky
  • 97,037
  • 24
  • 136
  • 212
1

Most STL implementations are not thread safe. You'll need to use thread synchronization (e.g. mutex) to prevent both threads from stomping on each other while accessing the vector. Basically, what you will need to do is create a class that contains the vector and a mutex and accessor functions that protect the vector for both reading and writing operations.

Zac Howland
  • 15,777
  • 1
  • 26
  • 42
  • @Gene: I think when people say "thread safe" they mean "able to use in threads without doing anything special." – John Dibling Dec 10 '10 at 15:27
  • This answer contains the same error as @pts’. Mutexes and synchronization are completely irrelevant here. – Konrad Rudolph Dec 10 '10 at 15:29
  • @John: Gene’s definition is as good as any’s. “thread safe” is a worthless qualification since no two people agree on its meaning. – Konrad Rudolph Dec 10 '10 at 15:30
  • @Konrad: I agree "thread safe" is a useless phrase. Just bringing another, possibly common perception. – John Dibling Dec 10 '10 at 15:32
  • @John Dibling -- "people" can "mean" many things, we are not here discussing psychology. YUou can't use the stable concepts any way you want, especially when such use makes no sense. – Gene Bushuyev Dec 10 '10 at 15:33
  • @John Dibling: "I agree "thread safe" is a useless phrase." Really, how about "Thread safety is a computer programming concept applicable in the context of multi-threaded programs..." -- http://en.wikipedia.org/wiki/Thread_safe – Gene Bushuyev Dec 10 '10 at 15:36
  • @Gene: When I say most are not thread safe, I'm saying that most implementations do not provide any protection for cross-thread access; they are designed to be single-threaded. It is the user's (the programmer using the STL implementation) job to make sure they take appropriate protection when using them in a multi-threaded solution. – Zac Howland Dec 10 '10 at 15:39
  • @Konrad: "Mutexes and synchronization are completely irrelevant here" - that statement is just plain wrong. – Zac Howland Dec 10 '10 at 15:41
  • @Zac: The OP has explicitly stated that concurrency was *not* the issue here because only one thread was accessing the vector. I was merely paraphrasing that when I said that synchronization and mutexes are irrelevant here. – Konrad Rudolph Dec 10 '10 at 16:06
  • @Konrad: It's very possible the OP was wrong about synch not being the problem. – John Dibling Dec 10 '10 at 16:08
  • @John: true, but only if the OP “lied” to us: “nobody is reading or writing from this vector except the cases I mentioned above”. If that is true, then no amount of mutexing is going to remove the problem. – Konrad Rudolph Dec 10 '10 at 16:11
  • @Konrad: "After some research, I narrowed down the problem to a push_back in a vector called from a different thread than the one in which the vector was created" - OP. If a vector is created in 1 thread, and has push_back calls in another, if there is any other operations going on (e.g. reading the vector) in the other thread, concurrency is the issue. Alternatively, he could have created the vector on the instance of "SomeClass" on the stack and tried to send the address of it to the other thread, which would cause non-concurrency problems. – Zac Howland Dec 10 '10 at 16:19
  • Its not that the OP may have lied, but rather did not provide enough information to narrow the set of potential pitfalls he could run into. – Zac Howland Dec 10 '10 at 16:20