pthread_join - wait for thread termination
(pthread_tryjoin_np pthread_timedjoin_np)非阻塞版本和超时版本
超时通过futex控制
/* Is the thread joinable?. */
if (IS_DETACHED (pd))
/* We cannot wait for the thread. */
return EINVAL;
每个线程都有一个joinid, 表示谁正在join该线程,如果pd->joinid == pd自身, 就是detached了
detached的线程在退出时会自己释放资源
pthread_detach 函数会设置该值
另外,如果设置了DETACHSTATE标志,那么pthread_create返回之前就会设置该值
pd->joinid = iattr->flags & ATTR_FLAG_DETACHSTATE ? pd : NULL;
struct pthread *self = THREAD_SELF;
int result = 0;
/* During the wait we change to asynchronous cancellation. If we
are canceled the thread we are waiting for must be marked as
un-wait-ed for again. */
pthread_cleanup_push (cleanup, &pd->joinid);
/* Switch to asynchronous cancellation. */
int oldtype = CANCEL_ASYNC ();
默认情况,线程是同步取消, 这意味这只有在某个遇到某个取消点才允许被取消, 换句话说
如果线程已经阻塞了,或者while(1); 线程是不会退出的
如果线程a试图join线程b,那么a被设置为异步取消,这样,只要有人试图pthread_cancel(a)
a将会退出
cleanup 函数在被取消的情况下会调用,其参数为&pd->joinid
它再次允许别的线程取消
- static void
-
cleanup (void *arg)
-
{//
-
/* If we already changed the waiter ID, reset it. The call cannot
-
fail for any reason but the thread not having done that yet so
-
there is no reason for a loop. */
-
(void) atomic_compare_and_exchange_bool_acq ((struct pthread **) arg, NULL,
-
THREAD_SELF);
-
}
- 原子的设置joinid为self,不允许别的线程再join该线程
/* Wait for the thread to finish. If it is already locked something
is wrong. There can only be one waiter. */
if (atomic_compare_and_exchange_bool_acq (&pd->joinid, self, NULL))
return EINVAL;
即如果joinid == NULL, 则设置其值为self, 如果 joinid != NULL则不做改动,标示它被别人join了
- /* Wait for the
child. */
-
lll_wait_tid (pd->tid);
该函数使用futex系统调用,直到pd->tid等于0
(内核会在thread退出的时候唤醒等待线程, 因为clone的时候使用了CLONE_CHILD_CLEARTID)
/* Remove the handler. */
pthread_cleanup_pop (0);
不执行cleanup函数
/* Store the return value if the caller is interested. */
if (thread_return != NULL)
*thread_return = pd->result;
/* Free the TCB. */
__free_tcb (pd);
阅读(3918) | 评论(0) | 转发(0) |