线程退出时如何通知等待者

一、线程退出
在之前的一篇博客(http://tsecer.blog.163.com/blog/static/150181720120175027358/)中说明了一个进程描述符的回收过程,其中可以看到,只有主线程有权利通知父进程整个线程组已经退出,也就宣告整个任务的结束,其它的线程(一般通过pthread_create创建)没有机会向父进程发送信号,也不能直接的wakeup父进程。但是在pthread线程库中,有时候我们又必须通过某种方法来通知其它对线程退出感兴趣的线程,例如,当线程创建之后,一个等待线程可能通过pthread_join来同步等待一个线程,也就是说,这个线程不消亡,等待着就没有勇气继续执行下去。
现在假设这个被等待的线程真的执行结束了,这个等待者将如何被唤醒呢?
二、C库实现
glibc-2.7\nptl\pthread_join.c
int
pthread_join (threadid, thread_return)
     pthread_t threadid;
     void **thread_return;
函数等待的位置:
  else
    /* Wait for the child.  */
    lll_wait_tid (pd->tid);这个等待其实最后就是执行sys_futex(WAIT)
看起来还是比较简单的吧。当然,很多看起来很简单的东西都不像它看起来的那么简单,所以这里也不能随便找个地方就开始等,这个位置也是需要精挑细选的,这个等待还要从线程的创建说起
__pthread_create_2_1--->>create_thread--->>>
  int clone_flags = (CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGNAL
             | CLONE_SETTLS | CLONE_PARENT_SETTID
             | CLONE_CHILD_CLEARTID | CLONE_SYSVSEM
#if __ASSUME_NO_CLONE_DETACHED == 0
             | CLONE_DETACHED
#endif
             | 0);
do_clone--->>>
  if (ARCH_CLONE (fct, STACK_VARIABLES_ARGS, clone_flags,这里通过__clone系统调用进入内核
          pd, &pd->tid, TLS_VALUE, &pd->tid) == -1)
三、内核实现
1、位置记录
在内核中
sys_clone--->>>do_fork--->>>copy_process
    p->clear_child_tid = (clone_flags & CLONE_CHILD_CLEARTID) ? child_tidptr: NULL;
所以内核保存了ARCH_CLONE中传递的pd->tid变量的位置进入在内核中,记录在被等待线程描述符的clear_child_tid指针中。
2、唤醒执行
pthread_exit--->>sys_exit--->>do_exit--->>>exit_mm--->>>mm_release
if (tsk->clear_child_tid
        && !(tsk->flags & PF_SIGNALED)
        && atomic_read(&mm->mm_users) > 1) {
        u32 __user * tidptr = tsk->clear_child_tid;
        tsk->clear_child_tid = NULL;

        /*
         * We don't check the error code - if userspace has
         * not set up a proper pointer then tough luck.
         */
        put_user(0, tidptr);
        sys_futex(tidptr, FUTEX_WAKE, 1, NULL, NULL, 0);
    }
至于为什么在mm中执行唤醒呢?我想可能是因为这个futex是依赖于mm_struct结构的吧。

posted on 2019-03-06 21:04  tsecer  阅读(496)  评论(0编辑  收藏  举报

导航