Compiling
Multithreaded Code
Two
potential problem areas that might arise when compiling multithreaded code are
header files and libraries. Header files might require adaptations for
multithreading, and multithreaded versions of supporting libraries might need
to be linked. In general, the compiler will make the correct decisions, but it
is important to be aware of these issues by reading the documentation when
encountering a new platform for the first time.
One
example of how the included header files might change in the presence of
mul-tiple threads is the errno variable on Solaris. Solaris provides different implementations of this
variable for single-threaded and multithreaded applications. In a
single-threaded application, there is only one errno variable, so this can be an
integer value. In a multi-threaded application, an errno variable needs to be defined for
each thread. The com-piler flag -mt passes the compiler flag -D_REENTRANT, which
makes the errno variable
a multithread-aware macro.
Listing
5.13 shows an example of a code that calls errno in a multithreaded context. Both
the main and child threads call fopen() with invalid parameters; the
child thread attempts to open the current directory for writing, and the main
thread attempts to write to an unspecified file. Both of these actions will
result in the value for errno being set to an error value.
Listing 5.13 Example
of Using errno in a Multithreaded
Application
#include <stdio.h> #include <errno.h>
#include <pthread.h>
void
* thread1( void* param )
{
FILE *fhandle = fopen( ".", "w" );
if ( !fhandle ) { printf( " thread1 %4i\n", errno ); } else { fclose(
fhandle ); }
}
int
main()
{
pthread_t thread_data1; int i;
pthread_create( &thread_data1, 0, thread1, 0 ); FILE *fhandle =
fopen( "", "r" );
if ( !fhandle ) { printf( " main %4i\n", errno ); } else { fclose( fhandle
); }
pthread_join( thread_data1, 0 );
}
Using Solaris Studio compilers on Solaris, the -mt flag ensures the correct behavior in multithreaded contexts. Listing
5.14 shows the results of compiling and running the application both with and
without the flag.
Listing 5.14 Running
a Multithreaded Code That Depends on errno
on Solaris
$
cc errno.c $ ./a.out
thread1 2
main 2
$
cc -mt errno.c $ ./a.out
thread1 22
main 2
When the code is correctly compiled, both of the
calls to errno produce
a value that is correct for the calling thread. When the -mt flag is omitted, the same value for errno is printed for both threads.
It is also necessary to ensure that the correct
libraries are linked into an application. Some support libraries include both
single-threaded and multithreaded versions, so selecting the appropriate one is
important. Some operating systems will explicitly require the Pthread library
to be linked into the application. For example, Solaris 9 would require an
explicit -lpthread compiler
flag; however, this changed in Solaris 10, when the threading library was
combined with the C runtime library, and the compiler flag was no longer
necessary.
The same situation is true when building with gcc.
The compiler has the flag -pthread, which
both passes the flag -D_REENTRANT and
causes linking with the POSIX threading library. However, not all platforms
need to define _REENTRANT; it
makes no difference to the Linux header files, so the only benefit is that the
compiler will include the POSIX threading library.
Some libraries are not multithread-safe; they do
not guarantee the correct answer when called by a multithreaded application.
For instance, the Solaris Studio compilers provide libfast, which is not multithread-safe but offers better performance than the
default malloc(). It is
easy to produce multithread-safe libraries using mutexes to ensure that only a
single thread can have access at a time. However, this does not produce a
library with performance that scales as the number of threads increases.
The other point to be aware of when compiling code that calls the POSIX
API is that it may be necessary to define particular variables in order to get
the correct versions of functions. These requirements are usually documented
under man standards. Linux
does not typically require this; however, Solaris does. For example, use of the
define - D_POSIX_C_SOURCE=199309L
will assert that the code is written to the
POSIX.1b-1993 standard. Failure to set the appropriate feature test macro will
usually cause warnings of undefined functions or of incompatible types being
passed into functions.
Related Topics
Privacy Policy, Terms and Conditions, DMCA Policy and Compliant
Copyright © 2018-2023 BrainKart.com; All Rights Reserved. Developed by Therithal info, Chennai.