执行的线程多于创建的线程

More threads executed than created

我正在学习线程编程。在执行以下示例时,我遇到了未定义的行为。

static void* print_thread_attr (void* param)
{
    pthread_attr_t attr;
    int detach_state = PTHREAD_CREATE_JOINABLE;

    pthread_getattr_np (pthread_self(), &attr);
    pthread_attr_getdetachstate (&attr, &detach_state);
    pthread_attr_destroy (&attr);

    printf("Detach state of thread [%u] pid [%d] is %s\n", pthread_self(), getpid(),
            (PTHREAD_CREATE_JOINABLE == detach_state)?
                    "JOINABLE THREAD":"DETACHED THREAD");
    return NULL;
}

void test_thread_attributes ()
{
    pthread_t thread_id1;
    pthread_t thread_id2;
    pthread_attr_t attr;

    printf("main pid [%d]\n", getpid());
    pthread_attr_init (&attr);
    pthread_create (&thread_id1, &attr, print_thread_attr, NULL);

    pthread_attr_init (&attr);
    pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
    pthread_create (&thread_id2, &attr, print_thread_attr, NULL);

    pthread_attr_destroy (&attr);
    pthread_join (thread_id1, NULL);

    //sleep (1);
}

1.Sometimes,它会打印:

main pid [3394]
Detach state of thread [88292160] pid [3394] is DETACHED THREAD
Detach state of thread [75705152] pid [3394] is JOINABLE THREAD
  1. 但有时

     main pid [3403]
     Detach state of thread [75705152] pid [3403] is JOINABLE THREAD
     Detach state of thread [88292160] pid [3403] is DETACHED THREAD
     Detach state of thread [88292160] pid [3403] is DETACHED THREAD
    

很奇怪,我只用了 2 次 pthread_create,但第二种情况打印了 3 次。使用 valgrind 检查时,第一种情况没有内存泄漏,但对于第二种情况,有 "possibly lost: 136 bytes in 1 blocks"

我想知道为什么在第二种情况下,线程 88292160 打印了两次? 此外,您可能会注意到注释掉的 sleep (1)。当我睡觉时 (1),我没有观察到第二种情况发生。

你有未定义的行为,因为你正在调用 pthread_attr_init() 两次,第二次是在一个已经初始化的对象上:

Calling pthread_attr_init() on a thread attributes object that has already been initialized results in undefined behavior.

对象attr被销毁后可以重新使用:

Once a thread attributes object has been destroyed, it can be reinitialized using pthread_attr_init(). Any other use of a destroyed thread attributes object has undefined results.

但是,您的代码无法保证该属性会在第一个线程被第二个线程重新初始化之前被销毁。因此,您可以使用两个不同的属性对象,甚至可以重复使用相同的属性(无需重新初始化)。但是,由于您在线程中销毁了该属性,因此在您的代码中无法使用此选项。

然而,最新的 POSIX standard 删除了用于重新初始化已初始化但已销毁的属性的引用未定义行为,并指出:

If an implementation detects that the value specified by the attr argument to pthread_attr_init() refers to an already initialized thread attributes object, it is recommended that the function should fail and report an [EBUSY] error.

我假设您的实现使用了一些旧版本并导致未定义的行为。无论如何,这是一个问题,您应该检查 pthread 函数的 return 值是否有错误。

看到的重复输出的实际问题是由于 issue with the stdio which is explained in an answer 此处的实施,这将解释为什么 sleep 似乎 "fix" 问题以及避免此问题的可能解决方法。