![](/img/trans.png)
[英]Trouble with converting single threaded HTTP server into multithreaded using pthreads
[英]pthreads: how to assert code is run in a single threaded context
我正在編寫一個C庫,在初始化期間需要fork()。 因此,我想斷言()應用程序代碼(在我的控制范圍之外)從單個線程上下文調用我的庫初始化代碼(以避免眾所周知的“ 線程和fork不混合 ”問題)。 一旦我的庫被初始化,它就是線程安全的(並且期望應用程序級代碼可以創建線程)。 我只關心支持pthreads。
使用pthreads計算當前進程空間中的線程數似乎是不可能的。 實際上,即使googletest也只在Mac OS和QNX上實現了GetThreadCount() 。
鑒於我無法計算線程,我是否可以在某種程度上斷言單線程上下文?
澄清:如果可能的話,我想避免使用“/ proc”(非可移植),附加庫依賴(如libproc)和LD_PRELOAD樣式的pthread_create包裝。
澄清#2:在我的情況下,使用多個進程是必要的,因為我的庫中的工作人員相對較重(使用webkit)並且可能崩潰。 但是,我希望原始流程能夠在工作人員崩潰中幸存下來。
您可以將庫初始化函數標記為在應用程序main()
之前運行。 例如,使用GCC,
static void my_lib_init(void) __attribute__((constructor));
static void my_lib_init(void)
{
/* ... */
}
另一個選擇是使用posix_spawn()
來分叉和執行工作進程作為單獨的從屬二進制文件。
編輯添加:
在我看來,如果你想確定進程是否已經創建(實際的,基於內核的)線程,你將不得不依賴於特定於操作系統的代碼。
在Linux的情況下,確定很簡單,並且在其他操作系統上也可以安全運行。 如果它無法確定當前進程使用的線程數,則該函數將返回-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;
}
在某些情況下(如chroot沒有/proc/
),即使在Linux中檢查也會失敗,因此-1
返回值應始終被視為未知而不是錯誤 (盡管errno
將指示失敗的實際原因)。
看一下FreeBSD手冊頁,我想知道相應的信息是否可用。
最后:
我沒有嘗試檢測有問題的情況,我認真推薦fork()
和exec()
(或posix_spawn()
)從屬進程,在子進程中只使用異步信號安全函數(參見man 7 signal
) exec()
),從而避免了fork() - 線程的並發症。 在forking()之前,您仍然可以創建任何共享內存段,套接字對等。 我能看到的唯一缺點就是你必須為奴隸工人使用單獨的二進制文件。 鑒於你對它們的描述,這對我來說聽起來不是一個缺點。
如果向進程'控制tty發送SIGINFO信號,則該進程應描述線程的狀態。 從描述中可以推斷出是否已經創建了任何線程。
您可能必須開發一個通過popen調用的小實用程序,以將輸出讀回到您的庫中。
添加了示例代碼Fri Dec 21 14:45
運行一個創建五個線程的簡單程序。 線程基本上睡覺了。 在程序退出之前,發送SIGINFO信號以獲取線程的狀態。
openbsd> cat a.c
#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 a.c -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
你可以使用pthread_once()
來確保沒有其他線程做同樣的事情:這樣你就不必關心多個線程正在調用你的初始化函數,只有一個線程會被真正執行。
使您的公共初始化函數通過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;
}
另一個例子可以在這里找到。
鏈接
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.