search    
Hewlett-Packard
Using Threads
The HP aC++ run-time environment supports multi-threaded applications. The following HP aC++ libraries are thread-safe with the limitations cited below:
  • Rogue Wave Standard C++ Library 2.2.1
    For 32-bit and 64-bit libraries:
    • libstd_v2.so and libstd_v2.a
    • libCsup.so and libCsup.a

  • Rogue Wave Standard C++ Library 1.2.1 and Tools.h++ 7.0.6
    For 32-bit and 64-bit libraries:
    • libstd.so and libstd.a
    • librwtool.so and librwtool.a
    • libCsup.so and libCsup.a
    • libstream.so and libstream.a
Using Locks
To guarantee that your I/O results from one thread are not intermingled with I/O results from other threads, you must protect your I/O statements with locks. For example:
// create a mutex and initialize it
pthread_mutex_t the_mutex;
#ifdef _PTHREADS_DRAFT4     // for user threads
pthread_mutex_init(&the_mutex, pthread_mutexattr_default);
#else                       // for kernel threads
pthread_mutex_init(&the_mutex, (pthread_mutexattr_t *)NULL);
#endif

pthread_mutex_lock(&the_mutex);
cout << "something" ... ;
pthread_mutex_unlock(&the_mutex);
Note that conditional compilation may be necessary to accommodate both the user threads and the kernel threads interfaces, as in the above example. An alternative might be to compose a buffer with an ostrstream and output with one write. The following example could be used with the cfront compatible libstream.
ostrstream ostr;
ostr << "something" /*...*/ ;
ostr << " or another" /*...*/ << endl;
cout.write(ostr.str(), ostr.pcount());
ostr.rdbuf()->freeze(0);
Note that the above example works with with the new library, though with the deprecated ostrstream. Or something similar can be done with the Rogue Wave Standard C++ Library 2.2.1 (libstd_v2) with standard ostringstream, as in the following example:
ostringstream ostr;
ostr << "something" /*...*/ ;
ostr << " or another" /*...*/ << endl;
cout.write(ostr.str().c_str(), ostr.str().length());
Note that cout.flush() may be needed if sharing the file with stdio.

Required Command-Line Options
To use the multi-thread safe capabilities of the Standard C++ Library, you need to specify the following options at both compile time and link time. Note that the options differ depending on which set of libraries you are using.
  • Rogue Wave Standard C++ Library 2.2.1

    • -D_RWSTD_MULTI_THREAD

    • -D_REENTRANT

    • -lpthread
      (This option applies only to kernel threads.)

    • -mt

  • Rogue Wave Standard C++ Library 1.2.1 and Tools.h++ 7.0.6

    • -D__HPACC_THREAD_SAFE_RB_TREE
      (Code compiled with this option is binary incompatible with code that is not compiled with this option. Only HP aC++ version A.01.21 and subsequent versions incorporate this option.)

    • -DRWSTD_MULTI_THREAD

    • -DRW_MULTI_THREAD
      (needed only for the Tools.h++ Library)

    • -D_REENTRANT

    • -lcma
      (This option applies only to user threads.)

    • -lpthread
      (This option applies only to kernel threads.)

    • -D_THREAD_SAFE
      (Unlike the other options in this table, this option is not required. You can use it with the cout, cin, cerr, and clog objects, if you are not using locks.)

    • -mt

Note: If you do not specify these options, a runtime error will be generated or multithread behavior will be incorrect. If you use +Oopenmp in an application, you must use -mt on files that are not compiled with +Oopenmp.

Limitations
In most cases, thread safety does not imply that the same object can be shared between threads. In particular, when objects have user visible state, it would not make sense to share them between threads.

Consider the following:

void f(ostream &out, int x, int y) {
       out << setw(3) << x << setw(10) << y;
}
This function is not be thread safe if called from multiple threads with the same object, since the width in the shared object can change at any time. Such objects are not protected from interactions between multiple threads, and the result of sharing such an object between threads is undefined.

If the same object is shared between threads, a runtime crash, abort, or intermingled output may occur. With the Rogue Wave Standard C++ Library 2.2.1, output may be intermingled but no aborts will occur.


Using -D_THREAD_SAFE with the cfront Compatible libstream

There is an exception to the above rule for the cfront compatible libstream. For the frequently used objects cout, cin, cerr, and clog, you can specify the -D_THREAD_SAFE compile time flag for any file that includes <iostream.h>. In this case, a new instance of the object is transparently created for each thread that uses it. All instances share the same file descriptor. The f() function in the above example will now work, because it receives one new out object per thread. However, the results of two simultaneous executions of f() will be mixed in any order in the output.

Using -D_THREAD_SAFE with the global scope operator is not supported for cout, cin, cerr, and clog.

For example, the following code would generate an error:

::cout << endl;
Note: If you use locks, you need not use the -D_THREAD_SAFE compile time flag since you are now responsible for ensuring thread safety.


Differences between Standard iostreams and cfront Compatible libstream

The cfront compatible libstream supports locking for each insertion. Rogue Wave Standard C++ Library 1.2.1 and Tools.h++ 7.0.6 do not support locking but do provide a thread private buffer.

Visible differences would be as follows:

  • In the case of standard iostreams, there is intermingling of each component being inserted.
  • With cfront compatible iostreams, there is intermingling of complete buffers (depending on when endl or flush is called).

Using -D__HPACC_THREAD_SAFE_RB_TREE

The Rogue Wave Standard C++ Library 1.2.1 (libstd) and Tools.h++ 7.0.6 (librwtool) are not thread safe if the underlying implementation rb_tree class is involved.

In other words, if the tree header file (which includes tree.cc) under /opt/aCC/include/ is used, these libraries are not thread safe. Most likely, it is indirectly referenced by including the standard C++ library container class map or set headers, or by including a RogueWave tools.h++ header like tvset.h, tpmset.h, tvmset.h, tpmap.h, tpmmap.h, tvmap.h, and tvmmap.h.

Since changing the rb_tree implementation to make it thread safe would break binary compatibility, the preprocessing macro, __HPACC_THREAD_SAFE_RB_TREE, must be defined. The macro is automatically defined in the Intel®-based environment.

A new object file compiled with the macro defined should not be linked with older ones that were compiled without the macro defined. Library providers whose library is built with the the macro defined may need to notify their users to also compile their source with the macro defined when the tree header is included.

Exception Handling
It is illegal to throw out of a thread. The following example illustrates that you cannot catch an object which has been thrown in a different thread. To do so will result in a runtime abort since HP aC++ finds no available catch handler and terminate is called.
#include <pthread.h>
void foo() {
   int i = 10;
   throw i;
}
int main() {
   pthread_t tid;
   try {
      ret=pthread_create(&tid, 0, (void*(*)(void*))foo, 0);
   }
   catch(int n) {}
}

Pthreads (Posix Threads)

Pthreads (POSIX threads) refers to the Pthreads library of thread-management routines. For information on Pthread routines see the pthread(3t) man page. To use the Pthread routines, your program must include the <pthreads.h> header file and the Pthreads library must be explicitly linked to your program.

Example:

aCC -mt  prog.c

Limitations

When using STL containers as local objects, the destructor will not get called when pthread_exit() is called, which leads to a memory leak. Do not call pthread_exit() from C++. Instead you must throw or return back to the thread's initial function. There you can do a return instead of pthread_exit().

Pthread library has no knowledge of C++ stack unwinding. Calling pthread_exit() for will terminate the thread without doing proper C++ stack unwind. That is, destructors for local objects will not be called. (This is analogous to calling exit() for single threaded program.)

This can be fixed by calling destructors explicitly right before calling pthread_exit().

Example:

#include <pthread.h>
#include <stdlib.h>
#include <exception>
 
extern "C" int printf(const char*...);
struct A { 
       A () { printf("ctor called\n"); }
      ~A () { printf("dtor called\n"); }
};
struct B { 
       B () { printf("B ctor called\n"); }
      ~B () { printf("B dtor called\n"); }
};
 
__thread A* pA;  // thread specific data.
 
void thread_specific_destroy(A *p) {
   delete p;
}
typedef void fp(void*);
void* foo(void*) {
   pA = new A();
   B ob;
   pthread_cleanup_push(reinterpret_cast<fp*>(thread_specific_destroy),pA);
   pthread_cleanup_pop(1);
   ob.~B();  // potential problem when the thread is canceled.
   pthread_exit(0);
   return 0;
}
int main() {
   //A oa; exit(0); 
   //dtor for oa won't be called if line above is uncommented.
   pthread_t thread_id;
   for (int i = 0; i < 3; i++)
      pthread_create(&thread_id, 0, &foo, 0);
   pthread_join(thread_id, 0);
}

Note: vector::clear() does not free all of the memory. The storage is put back into a free pool for that one container.

This does not happen if a thread is canceled. In such cases, use thread specific data or thread local storage support along with pthread_cleanup_[push|pop] utilities.

pthread_cancel is not supported.
Function Scoping

The set_terminate(), set_unexpected(), and set_new_handler(), functions apply to all threads in the process. For information on specific functions refer to the appropriate library documentation.

Performance Options

You can use the -D__HPACC_FIXED_REFCNT_MUTEX flag to reduce the amount of space used for string mutexes and thereby increase performance when using either -AA or -AP strings. Instead of having one mutex per string, there will be a fixed array of mutexes shared among all strings. This feature requires C++ runtime version A.05.61 or newer. For additional information refer to the -mt option.

The number of string mutexes defaults to 64 and can be configured by:

     export aCC_MUTEX_ARRAY_SIZE=## 
You can mix code compiled with and without -D__HPACC_FIXED_REFCNT_MUTEX.