我正在研究线程编程。在做下面的例子时,我得到了未定义的行为。
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
但有时
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
这很奇怪,因为我只使用pthread_create 2次,但是第2次打印3次。使用valgrind进行检查时,第一种情况下没有内存泄漏,但对于第二种情况,“可能丢失:1个块中有136个字节”
我需要知道为什么在第二种情况下,线程88292160打印两次? 此外,您可能会注意到已注释掉的睡眠(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
似乎"修复"问题和可能的解决方法,以避免这个问题。