ライブラリ初期化関数を、アプリケーションの前に実行するようにマークすることができますmain()
。たとえば、GCCを使用すると、
static void my_lib_init(void) __attribute__((constructor));
static void my_lib_init(void)
{
/* ... */
}
もう1つのオプションはposix_spawn()
、ワーカープロセスを個別のスレーブバイナリとしてフォークして実行するために使用することです。
追加するために編集:
プロセスがすでに(実際のカーネルベースの)スレッドを作成しているかどうかを判断したい場合は、OS固有のコードに依存する必要があるように思われます。
Linuxの場合、決定は簡単で、他のOSでも安全に実行できます。現在のプロセスで使用されているスレッドの数を判別できない場合、関数は-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;
}
/proc/
Linuxでもそのチェックが失敗する場合があります(chroot withoutなど)。そのため、-1
戻り値はエラーではなく常に不明として扱われる必要があります(ただし、失敗の実際の理由が示されます)。errno
FreeBSDのマニュアルページを見ると、対応する情報がまったく入手できないのではないかと思います。
ついに:
問題のあるケースを検出しようとするのではなく、子プロセス(の前)で非同期シグナルセーフ関数(を参照)のみを使用して、フォーク()スレッドの複雑さを回避することfork()
を真剣に推奨します。forking()の前に、共有メモリセグメント、ソケットペアなどを作成できます。私が見ることができる唯一の欠点は、スレーブワーカーに別々のバイナリを使用する必要があることです。それらの説明を考えると、これは私にとって欠点のようには聞こえません。exec()
posix_spawn()
man 7 signal
exec()