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.
|
|
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 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. Whether or not this macro is defined when compiling
a file that includes the tree header, its use must be
consistent. For example, 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.
|
|
When pthread_exit is called in multithreaded C++ applications, the
exiting or cancelled thread exits without calling destructors for the active
local objects. This behavior is not always desirable, certain applications might
require the destructors to be called for objects on the stack of exiting thread.
From this release, support is provided for calling destructors for active
local objects when pthread_exit is called on a thread. To enable this
feature you need to set the environment variable aCC_PTHREAD_EXIT_CLEANUP=1|ON.
Consider the following example:
#include <pthread.h>
#include <stdio.h>
class A {
public :
A() { printf("A()\n"); }
~A() { printf("~A()\n"); }
};
void foo() {
A a2;
pthread_exit((void *) 77);
}
void* bar(void *inThread) {
A a1;
foo();
return 0;
}
int main() {
pthread_t tid;
if (pthread_create(&tid, 0, &bar, NULL)) {
perror("pthread create failed\n");
}
pthread_join(tid, NULL);
return 0;
}
With this feature enabled, for this example, both the constructors and
destructors will get called for local variables a1 and a2 in
functions foo and bar.
This feature requires exception handling information and if functions are
compiled with +noeh, no destructors will be called with no indication
of a problem. This is similar to mixing and matching +eh code with
+noeh code and doing a throw across the mixture.
This feature is available only in the shared version of C++ runtime library.
Also, this feature is available only on HP-UX 11.x versions for PA.
|