【问题标题】:Why is it undefined if multiple threads join a thread?如果多个线程加入一个线程,为什么它是未定义的?
【发布时间】:2019-09-10 14:57:44
【问题描述】:

如果我有多个线程并且我想等待一个线程完成,为什么根据 pthread_join() 函数这是未定义的?

例如,下面的代码显示线程 1 和 2 等待线程 0:

void* thread1(void* t1){
..
pthread_join(pthread_t thread0, void **retval1);
return NULL
}

void* thread2(void* t2){
..
pthread_join(pthread_t thread0, void **retval2);
return NULL
}

为什么这种行为是未定义的,或者换句话说是不可能的?

【问题讨论】:

  • 我认为这个例子需要代码,因为你在这里似乎有一个误解。两个线程的连接不是对称操作。 IE。如果线程A1加入B,然后线程A2加入B就可以了。这意味着B等待A1完成,然后等待A2完成。不能让 B1 和 B2 都等待线程 A 完成。
  • 后一种情况就是我所指的。我将包含代码来说明这一点。
  • 顺便说一句,请注意,POSIX 还使线程 B 无法等待 A1 and A2A1 or A2。你必须等待A1,然后等待A2,如果你不知道哪个会先完成,这有点麻烦。相比之下,Windows 有WaitForMultipleObjects。这更加灵活。
  • @MSalters 我知道线程只能在 linux 中等待一个线程,但我不明白为什么多个线程不能等待一个线程完成。是什么阻止他们这样做?
  • 您是在问为什么不能调用 pthread_join 两次,还是在寻求一种方法来完成您正在尝试做的事情?

标签: c linux multithreading pthreads


【解决方案1】:

pthread_t 对象通常会指向与线程相关的一些已分配数据。这些数据当中一般会是线程的返回值。 pthread_join 将读取返回值并释放线程数据。

如果你pthread_join 两次相同的 pthread id,你就会遇到双重释放的情况。指向的数据在第二次连接时可能无效,但它也可能被另一个线程以不可预知的方式重用。

结果很难/不可能推理。因此,UB。

【讨论】:

  • 为了避免这样的问题,为什么不把它放在堆栈中呢?
  • @duper21:把什么放在什么栈里?
  • @duper21 线程需要自己的堆栈。您只能在堆栈中容纳这么多堆栈,并且堆栈分配的线程数据将在 pthread_create-caller 时失效(pthread_create 还需要是一个宏,否则它将无法在其“调用者”中分配堆栈数据“) 回来。线程应该是堆分配的(或等效的)。
  • @PSkocik 是否正确地说返回值必须可供其他线程使用,因此必须放在堆中,这就是可能出现“双重释放”问题的原因?
  • @duper21:哪个堆栈? thread0thread1 加入后不会有堆栈,所以thread2 仍然失败。并且前面的 C 不会知道 thread1 将进行连接,因此它也不能使用该堆栈。
【解决方案2】:

基本上,thread0retval 会一直存储到一个 线程调用pthread_join。之后,retval 将不再可用。

C++ 有std::shared_future,它被明确地设计成多个线程可以等待一个结果,这表明你的想法并不奇怪。

【讨论】:

  • 如果它包含在 C++ 中,为什么它在 C 中不可用?
  • @duper21:C++ 有析构函数,因此很容易跟踪有多少std::shared_future 实例在等待结果。 C 无法跟踪仍然存在多少 pthread_t 值。
【解决方案3】:

pthread_join 是一种资源标识符释放操作,例如文件描述符上的close、分配的内存上的free、文件名上的unlink 等等。所有这些操作本质上都受“双重释放”的约束/"use-after-free" 如果标识符(这里是构成pthread_t 值的特定位模式)将来可以再次使用,则会出现错误。因此,行为必须要么完全未定义,要么受制于使其成为严重编程错误的条件,甚至可能是未定义的。

请注意,在您的心智模型中,您可能会想到两个pthread_join 调用“在线程退出之前开始”,因此发生在pthread_t 标识符仍然有效的时间。然而,形式上它们之间没有顺序,也不可能存在。 “已经在pthread_join 中被阻止”和“即将调用pthread_join”状态之间没有明显的区别。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-05-14
    • 1970-01-01
    • 2023-02-26
    • 1970-01-01
    • 1970-01-01
    • 2013-11-25
    • 1970-01-01
    • 2013-06-16
    相关资源
    最近更新 更多