Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the correct way to build a thread-safe, multiplatform C library?

Consider the following trivial C program,

#include <errno.h>
int
main(int argc, char* argv[]) {
  return errno;
}

When compiled on Solaris, the behavior of this code is dependent on the presence of -D_REENTRANT.

solaris$ cc -E test.c | grep return
  return errno;
solaris$ cc -D_REENTRANT -E test.c | grep return
  return  ( * ( ___errno ( ) ) );

with the latter version being thread-safe. If we compile the same code on Linux, we get the same behavior independent of -D_REENTRANT

linux$ gcc -E test.c | grep return
  return (*__errno_location ());
linux$ gcc -D_REENTRANT -E test.c | grep return
  return (*__errno_location ());

Solaris' cc has the option -mt, which implies -D_REENTRANT, as does gcc's -pthread. However, for a library, specifying these multi-threaded options seems poor, as it injects an unnecessary dependency on the threading runtime. However, if the library needs to be thread-safe (including errno), then the thread-safe semantics are needed at both compile time of the library and of the deriving code. On Linux, this is easy, because errno is always thread-local, but that's not guaranteed on other systems as just demonstrated.

That results in the question: how is a thread-safe library properly compiled and distributed with headers? One option would be to #define _REENTRANT in the main header, but this would cause issues if #include <errno.h> occurs before the library header inclusion. Another option is to compile the library with -D_REENTRANT, and have the main header #error if _REENTRANT is not defined.

What's the correct/best way to make a thread-safe library and ensure it correctly inter-operates with the code it is linked with?

like image 686
Alexander Chernyakhovsky Avatar asked Apr 11 '13 09:04

Alexander Chernyakhovsky


People also ask

What are thread-safe libraries?

Software libraries can provide certain thread-safety guarantees. For example, concurrent reads might be guaranteed to be thread-safe, but concurrent writes might not be. Whether a program using such a library is thread-safe depends on whether it uses the library in a manner consistent with those guarantees.

Are C functions thread-safe?

The standard C printf() and scanf() functions use stdio so they are thread-safe. The standard C printf() function is susceptible to changes in the locale settings if called in a multithreaded program.


1 Answers

I don't have access to any Solaris machine at the moment, so I can't test this. But what happens when you put #define _POSIX_C_SOURCE 200112L as the very first line in test.c (before inclusion of <errno.h>)? If your Solaris is POSIX-compliant, then that should make errno expand to the thread-safe version. This is because POSIX defines errno as below:

For each thread of a process, the value of errno shall not be affected by function calls or assignments to errno by other threads.

Accordingly, this is portable to any POSIX-compliant system. In fact, if you want to write POSIX-compliant application code, then you should always define _POSIX_C_SOURCE to the value appropriate for the minimum version of POSIX you are targeting. The definition should be at the top of every source file before including any headers. From the 2001 version of the standard:

A Strictly Conforming POSIX Application is an application that requires only the facilities described in IEEE Std 1003.1-2001. Such an application:

...

8. For the C programming language, shall define _POSIX_C_SOURCE to be 200112L before any header is included

like image 66
Dan Moulding Avatar answered Sep 27 '22 16:09

Dan Moulding