NPTL中的pthread_t

前几天一个程序老是出现段错误,最后实在找不到地方,用gdb单步,发现问题出现在一个回调函数的pthread_cancel中。这个问题就奇怪了。《Unix系统编程》上说了pthread_cancel没有定义必须检测的错误,而且,当ptherad_cancel(pthread_t thread)时,若thread对应的线程不存在,只是返回ESRCH而已。但是问题是,这里就是因为程序第一次执行,除了主线程外,没有其他线程存在,而且因为这个thread变量是全局变量,应该是被自动初始化为零的。也就是说pthread_cancel(0),会引起段错误。

然后,我试用了所谓用pthread_kill给一个thread发送信号0来判断该线程是否存在的方法,发现这样其实也引起段错误。但是我查看pthread_t的类型定义,发现在pthread.h中,它就是定义为:

typedef unsigned long int pthread_t;

非常清楚明了,我以为它就像是pid_t之类一样就是一个标识符号呢,但是它为什么引起段错误呢?无奈,最后查看了glibc中nptl目录中的源码,这才发现pthread_cancel函数的第一行赫然写着:

volatile struct pthread *pd = (volatile struct pthread *) th;

原来,pthread_t是一个指针!但是,为什么非得把它定义成整数混淆视听呢??我知道指针本质就是整数,但是还是被忽悠了~不可理解~反正pthread_t定义成结构都可以,为什么不直接定义成指针呢?为了和Linux Thread兼容吗?这个,反正我是想不通。

它指向的那个struct pthread结构就是线程描述符定义在descr.h中,里边内容很多,就包括线程的pid和tid。而在pthread_cancel和pthread_kill开始都有是用INVALID_PD_P来判断这个结构来判断pthread_t thread代表的线程是否有效。判断的原理是tid是否小于等于0。自然会读这个结构的成员,当pthread的值指向不被允许访问的内存位置,比如零地址的时候,段错误就是在函数判断这个pthread是否有效的时候就发生了。

但是,我的程序里我没法控制用户在任何线程的pthread_t都被创建过了才点击取消按钮。最后采用很凑合的方法,在程序初始化的时候,被每个pthread_t型的变量都创建一个线程,将那个值初始化到有效范围内。自己都感觉很扯~

唉,在凑合中继续~

《NPTL中的pthread_t》有7条评论

  1. to ostric:
    确实是pthread_cancel(0)引起段错误,但是并不是只有pthread_cancel(0),引起段错误。这个对入口参数的进行合法性检查我试过了,我说的很清楚,我使用了平常的判断一个线程是否存在的方法去判断这个pthread_t是否合法,但是很遗憾,这个pthread_t的定义和使用方法,注定了这个段错误在判断时候就发生了。pthread_t的范围不是非零即可,其有效范围貌似不固定,所以才用了创建一个线程来用它初始化这个pthread_t型的数据的土办法,这个实现,确实不好用,对pthread_t是否合法本身我没有找到到合理的判断它是否有效的手段。您若有,请赐教。

    回复
  2. 既然pthread_cancel(0)会引起段错误,你为什么不在调用前对入口参数进行判断?单单为了cancel就创建一个多余的线程,当然非常不合理了。另外to luguo:Nothing sucks.

    回复

回复 Amankwah 取消回复

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据