前几天一个程序老是出现段错误,最后实在找不到地方,用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型的变量都创建一个线程,将那个值初始化到有效范围内。自己都感觉很扯~
唉,在凑合中继续~
to ostric:
确实是pthread_cancel(0)引起段错误,但是并不是只有pthread_cancel(0),引起段错误。这个对入口参数的进行合法性检查我试过了,我说的很清楚,我使用了平常的判断一个线程是否存在的方法去判断这个pthread_t是否合法,但是很遗憾,这个pthread_t的定义和使用方法,注定了这个段错误在判断时候就发生了。pthread_t的范围不是非零即可,其有效范围貌似不固定,所以才用了创建一个线程来用它初始化这个pthread_t型的数据的土办法,这个实现,确实不好用,对pthread_t是否合法本身我没有找到到合理的判断它是否有效的手段。您若有,请赐教。
既然pthread_cancel(0)会引起段错误,你为什么不在调用前对入口参数进行判断?单单为了cancel就创建一个多余的线程,当然非常不合理了。另外to luguo:Nothing sucks.
to Kermit Mei:
呵呵,是啊,现在要下功夫的东西太多,快疯了~
pthread的使用确实得下一番功夫啊……
to wind:
怎么没有时间啊?这个是上个月写的!
to luguo:
您现在怎么什么都sucks了,太……
这就是为什么thread sucks~
怎么没显示写的时间啊?是不是就是昨晚熬夜写的啊 ?