views:

99

answers:

2

I posted a previous question "Seg Fault when using std::string on an embedded Linux platform" where I got some very useful advise. I have been away on other projects since then and have recently returned to looking at this issue.

To reiterate, I am restricted to using the arm-linux cross compiler (version 2.95.2) as this is what is supplied and supported by the embedded platform vendor. I understand that the issue is likely because the stdlib is very old, and not particularly thread safe.

The problem is that whenever I use the STL containers in multiple threads, I end up with a segmentation fault. The code below will consistently seg fault unless I use pthread_mutex_lock and scope operators around the container declarations (as in other post).

It is not feasible to use this approach in my application as I pass the containers around to different methods and classes. I would ideally like to solve this problem, or find a suitable alternative. I have tried STLPort and SGI's Standard Template Library with the same results. I can only assume that because they are being linked by the very old gcc, they cannot solve the problem.

Does anyone have any possible recommendations or solutions? Or perhaps you can suggest an implementation of vector (and string) that I can drop into my code?

Thanks in advance for any guidance.

#include <stdio.h>
  #include <vector>
  #include <list>
  #include <string>

  using namespace std;
    /////////////////////////////////////////////////////////////////////////////

    class TestSeg
    {
     static pthread_mutex_t     _logLock;
     public:
      TestSeg()
      {
      }

      ~TestSeg()
      {
      }

      static void* TestThread( void *arg )
      {
       int i = 0;
       while ( i++ < 10000 )
       {
        printf( "%d\n", i );
        WriteBad( "Function" );
       }
       pthread_exit( NULL );
      }

      static void WriteBad( const char* sFunction )
      {
       //pthread_mutex_lock( &_logLock );
       //{

       printf( "%s\n", sFunction );
       string sKiller;     //       <----------------------------------Bad
       //list<char> killer;    //       <----------------------------------Bad
       //vector<char> killer;    //       <----------------------------------Bad

       //}
       //pthread_mutex_unlock( &_logLock );

       return;
      }

      void RunTest()
      {
       int threads = 100;
       pthread_t     _rx_thread[threads];
       for ( int i = 0 ; i < threads ; i++ )
       {
        pthread_create( &_rx_thread[i], NULL, TestThread, NULL );
       }

       for ( int i = 0 ; i < threads ; i++ )
       {
        pthread_join( _rx_thread[i], NULL );
       }
      }

    };

    pthread_mutex_t       TestSeg::_logLock = PTHREAD_MUTEX_INITIALIZER;

    int main( int argc, char *argv[] )
    {
     TestSeg seg;
     seg.RunTest();
     pthread_exit( NULL );
    }
+2  A: 

Part of your query might be answered in another thread. The design of C++, including the standard library, is influenced by many factors. Efficiency is a repeated theme. Thread safety mechanisms often are at odds with an objective of efficiency. The age of the library is not really the issue.

For your situation, you may be able to wrap the STL vector in your own vector class (you might consider a Decorator) that contains the locking mechanism and provides the lock/unlock logic around accesses.

gregg
+6  A: 

The issue is not with the containers, it's with your code.

It is completely unnecessary to make the containers themselves threadsafe, because what you need, first and foremost, is transaction-like semantics.

Let's assume, for the sake of demonstration, that you have a threadsafe implementation of vector, for example.

  • Thread 1: if (!vec.empty())
  • Thread 2: vec.clear();
  • Thread 1: foo = vec.front();

This leads to undefined behavior.

The issue is that having each operation on the container threadsafe is pretty much pointless because you are still required to be able to lock the container itself for several operations in a row. Therefore you would lock for your various operations, and then lock again on each and every operation ?

As I said: completely unnecessary.

Matthieu M.
Matthieu, I fully appreciate what you are saying and understand that there would be undefined behaviour when sharing the container instance between threads. However the problem I am having is that the local stack instances are stepping on each others toes. Why would I need to lock a local variable?
Brad
It could be if your memory allocation scheme wasn't threadsafe. It's possible that by default your compiler uses a non-threadsafe `malloc`/`new` and that it will get unto a threadsafe version if you pass the right option... but now that is a far fetched guess. As for `static` variables: the STL code is quite readable, you should be able to browse the implementation (of `vector` for example).
Matthieu M.