【问题标题】:What happens if two threads call fork() simultaneously如果两个线程同时调用 fork() 会发生什么
【发布时间】:2019-11-03 06:28:48
【问题描述】:

我有一个多线程的进程。我已经使用 __register_atfork(blocksigprof,restoresigprof,NULL,NULL); 注册了准备函数和父处理程序 功能。 现在让我们假设两个线程同时调用 fork。我在 blocksigprof 中有一个计数器增量,在 restoresigprof 中有一个计数器减量。

考虑到上述情况,blocksigprof 和 restoresigprof 是否总是成对调用? __register_atfork 中是否存在任何固有的锁定机制。

#define NUM_THREADS 8
static int go=0;
static int exec = 1;
static int ev_od = 0;

static void *
test_thread (void *arg) {
    int j;
    pid_t c, d;
    while(!go) // Wait, so that all threads are here.
        continue;
    // All will fork, hopefully at same time because of go signal wait.
    while(exec) {
        c = fork();
        if (c < 0) {
            printf("SANJAY: fork() failed.\n");
            exit(1);
        } else if (c == 0) { // Child
            exit(0);
        }
        else { // parent
            d = waitpid(c, NULL, 0); 
        }
    }   
    return NULL;
}

extern int __register_atfork(void (*)(void),void (*)(void),void (*)(void),void *); 
static sigset_t s_new;
static sigset_t s_old;
static int count = 0;
static void blocksigprof(void){
    count++;
#ifdef SYS_gettid
    pid_t tid = syscall(SYS_gettid);
    if (tid % 2) {
        printf("sleep.\n");
        usleep(1);
    }
#else
#error "SYS_gettid unavailable on this system"
#endif
    printf("Pre-fork. Count should be one. %d\n", count);
}
static void restoresigprof(void){
    printf("Post-fork. Count should be one. %d\n", count);
    count--;
}
int
main () {
    pthread_t t[NUM_THREADS];
    void *ptr;
    long size = 500 * 1024 * 1024;
    int i, m;
    volatile int result = 0;
    int g_iters = 100;

    (void) __register_atfork(blocksigprof,restoresigprof,NULL,NULL);
    // Increase size, so fork takes time.
    printf("SANJAY: Increasing process size.\n");
    ptr = malloc(size);
    memset(ptr, 0,  size);
    ptr = malloc(size);
    memset(ptr, 0,  size);
    ptr = malloc(size);
    memset(ptr, 0,  size);
    ptr = malloc(size);
    memset(ptr, 0,  size);
    ptr = malloc(size);
    memset(ptr, 0,  size);
    ptr = malloc(size);
    memset(ptr, 0,  size);
    ptr = malloc(size);
    memset(ptr, 0,  size);
    ptr = malloc(size);
    memset(ptr, 0,  size);
    ptr = malloc(size);
    memset(ptr, 0,  size);
    // Create threads.
    for (i = 0; i < NUM_THREADS; ++i) {
        pthread_create(&t[i], NULL, test_thread, NULL);
    }

    printf("SANJAY: Killing time.\n");
    // Kill time, so that all threads are at same place post it, waiting for go. 100M cycles.
    for (m = 0; m < 1000000; ++m)
        for (i = 0; i < g_iters; ++i )
            result ^= i;
    // Give all threads go at same time.
    printf("SANJAY: Let threads execute.\n");
    go = 1;
    usleep(10000000); // Wait for 10 sec.
    exec = 0;
    // Wait for all threads to finish.
    for (i = 0; i < NUM_THREADS; ++i) {
        pthread_join(t[i], NULL);
    }
    printf("SANJAY: Done.\n");

    return 0;
}

【问题讨论】:

  • 你为什么不用pthread_atfork

标签: linux multithreading process kernel fork


【解决方案1】:

pthread_atfork 规范不要求其实现序列化对prepareparent 处理程序的调用,因此可以安全地假设没有同步。

glibc implementation does lock an internal mutex 防止多个线程并行进入处理程序。但是,这是一个实现细节。代码中的 cmets 说这样的实现不符合 POSIX,因为 POSIX 要求 pthread_atfork 是异步信号安全的,并且在那里使用互斥锁使其不异步信号安全。

为了使您的代码健壮,我建议使用原子或互斥锁来保护您的共享状态免受竞争条件的影响。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-03-18
    • 1970-01-01
    • 1970-01-01
    • 2014-03-27
    • 1970-01-01
    • 1970-01-01
    • 2011-11-19
    • 1970-01-01
    相关资源
    最近更新 更多