Pthreads: how to claim code runs in a single threading context

I am writing a C library that requires fork () initialization. Therefore, I want to assert () that the application code (which is out of my control) calls my library initialization code from a single thread (to avoid the known " thread and fork do not mix " problem). Once my library was initialized, it is thread safe (and it is expected that application level code can create threads). My only concern is pthreads support.

It seems impossible to count the number of threads in the current process space using pthreads. Indeed, even googletest implements GetThreadCount () on Mac OS and QNX.

Given that I cannot count threads, is it possible that I can claim a single thread context instead?

Explanation. If possible, I would like to avoid using "/ proc" (not portable), an additional library dependency (like libproc), and pthread_create wrappers in the LD_PRELOAD style.

Clarification # 2: In my case, the use of several processes is necessary, since the workers in my library are relatively heavy (using webkit) and may crash. However, I want the initial process to withstand operational failures.

+7
source share
3 answers

You can mark the library initialization function, which must be run before the main() application. For example, using GCC,

 static void my_lib_init(void) __attribute__((constructor)); static void my_lib_init(void) { /* ... */ } 

Another option is to use posix_spawn() for fork and execute workflows as separate, subordinate binaries.

EDIT ADD:

It seems to me that if you want to determine if a process has actually created (actual, kernel-based) threads, you will have to rely on OS-specific code.

In the case of Linux, the definition is simple and safe to work on other OSs. If it cannot determine the number of threads used by the current process, the function will return -1:

 #include <unistd.h> #include <sys/types.h> #include <dirent.h> #include <errno.h> int count_threads_linux(void) { DIR *dir; struct dirent *ent; int count = 0; dir = opendir("/proc/self/task/"); if (!dir) return -1; while (1) { errno = 0; ent = readdir(dir); if (!ent) break; if (ent->d_name[0] != '.') count++; } if (errno) { const int saved_errno = errno; closedir(dir); errno = saved_errno; return -1; } if (closedir(dir)) return -1; return count; } 

There are certain cases (for example, chroot without /proc/ ) where this check will fail even on Linux, so a return value of -1 should always be considered unknown, not an error (although errno will indicate the actual reason for the failure).

Looking at the FreeBSD man pages, I wonder if the relevant information is available at all.

Finally:

Instead of trying to identify a problematic case, I seriously recommend fork() and exec() (or posix_spawn() ) subordinate processes, using only functions safe for asynchronous access (see man 7 signal ) in the child process (before exec() ), thereby avoiding the complications of fork () threads. You can create shared memory segments, pairs of sockets, etc. Before forking (). The only drawback that I see is that for slave traders you need to use separate binary files. Which, given your description of them, does not seem to me a flaw.

+2
source

If you send a SIGINFO signal to a tty control process, the process should describe the state of the threads. From the description, it should be possible to determine if any threads have been created.

You may need to develop a small utility that is called via popen to read the output back to your library.

Added code sample Fri Dec 21 14:45

Run a simple program that creates five threads. The topics are mostly sleeping. Before exiting the program, send a SIGINFO signal to get the status of the streams.

 openbsd> cat ac #include <unistd.h> #include <pthread.h> #define THREADS 5 void foo(void); int main() { pthread_t thr[THREADS]; int j; for (j = 0; j < THREADS; j++) { pthread_create(&thr[j], NULL, (void *)foo, NULL); } sleep(200); return(0); } void foo() { sleep(100); } openbsd> gcc ac -pthread openbsd> a.out & [1] 1234 openbsd> kill -SIGINFO 1234 0x8bb0e000 sleep_wait 15 -c---W---f 0000 0x8bb0e800 sleep_wait 15 -c---W---f 0000 0x8bb0e400 sleep_wait 15 -c---W---f 0000 0x7cd3d800 sleep_wait 15 -c---W---f 0000 0x7cd3d400 sleep_wait 15 -c---W---f 0000 0x7cd3d000 sleep_wait 15 -c---W---f 0000 main 
+1
source

You can use pthread_once() so that no other thread does the same: in this way, you must ensure that multiple threads call your initialization function, only one will actually be executed.

Make your public initialization function run private initialization via pthread_once() .

 static pthread_once_t my_initialisation_once = PTHREAD_ONCE_INIT; static void my_initialisation(void) { /* do something */ } int lib_initialisation(void) { pthread_once(&my_initialisation_conce, my_initialisation); return 0; } 

Another example can be found here .

References

-one
source

All Articles