执行的线程多于创建的

时间:2015-05-07 09:19:46

标签: c linux multithreading pthreads

我正在研究线程编程。在做下面的例子时,我得到了未定义的行为。

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.有时会打印出来:

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 2次,但是第2次打印3次。使用valgrind进行检查时,第一种情况下没有内存泄漏,但对于第二种情况,“可能丢失:1个块中有136个字节”

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

1 个答案:

答案 0 :(得分:1)

您有未定义的行为,因为您已经两次调用pthread_attr_init()而第二次调用已初始化的对象:

  

在具有的线程属性对象上调用pthread_attr_init()   已经初始化的结果是未定义的行为。

对象attr如果被销毁则可以重复使用:

  

一旦线程属性对象被破坏,它就可以了   使用pthread_attr_init()重新初始化。任何其他使用被破坏的   线程属性对象具有未定义的结果。

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

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

  

如果实现检测到attr指定的值   pthread_attr_init()的参数是指已经初始化的   线程属性对象,建议该函数应该   失败并报告[EBUSY]错误。

我假设你的实现使用了一点旧并导致未定义的行为。在任何情况下,这都是一个问题,您应该检查pthread函数的返回值是否有错误。

看到重复输出的实际问题是由issue with the stdio实施的an answer实现的,这可以解释为什么sleep似乎"修复"问题和可能的解决方法,以避免这个问题。