前几天一个程序老是出现段错误,最后实在找不到地方,用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中,它就是定义为:
非常清楚明了,我以为它就像是pid_t之类一样就是一个标识符号呢,但是它为什么引起段错误呢?无奈,最后查看了glibc中nptl目录中的源码,这才发现pthread_cancel函数的第一行赫然写着:
原来,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型的变量都创建一个线程,将那个值初始化到有效范围内。自己都感觉很扯~
唉,在凑合中继续~