Chapter: Multicore Application Programming For Windows, Linux, and Oracle Solaris - Using POSIX Threads

| Study Material, Lecturing Notes, Assignment, Reference, Wiki description explanation, brief detail |

Compiling Multithreaded Code

Two potential problem areas that might arise when compiling multithreaded code are header files and libraries.

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.


Study Material, Lecturing Notes, Assignment, Reference, Wiki description explanation, brief detail


Copyright © 2018-2020 BrainKart.com; All Rights Reserved. Developed by Therithal info, Chennai.