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.
Nominal animal
source share