今天下午我遇到了一些棘手的问题,因为在mips64
上编译程序,经常出现程序编译不出来,或者运行不正常,花了很长的时间定位,最后和同事一些解决了,下面分享出来我提炼出来的一些核心定位问题的步骤。
子线程创建不出来
猜测:go
的程序都能创建出子线程,但是c++
的创建不出来,但是在 x86 可以,是不是什么 linux 系统限制?
![98bd2c4d2509454cc665196f971fd0c6.png](https://i-blog.csdnimg.cn/blog_migrate/4860ab59cad5afcf62ba4dea3a5094cc.jpeg)
![192141df64b736322056b49c06835e6b.png](https://i-blog.csdnimg.cn/blog_migrate/e9ef9df285781500720216f9ef7a17d2.png)
解决方法:加错误日志进行调试(最 lower 办法)
找到报错点:
![d713060cd144ea9916086d7aefd8fd44.png](https://i-blog.csdnimg.cn/blog_migrate/c86a0054291c1e84f40e77c0fe9ef1eb.jpeg)
查询 man
手册,看看是不是能找到有帮助的东西
man pthread_attr_setstacksize
打印出解释
ERRORS
pthread_attr_setstacksize() can fail with the following error:
EINVAL The stack size is less than PTHREAD_STACK_MIN (16384) bytes.
On some systems, pthread_attr_setstacksize() can fail with the error EINVAL if stacksize is not a multiple of the system page size.
翻译上面的话,可能会产生这个错误
EINVAL
堆栈大小小于PTHREAD_STACK_MIN(16384)
字节。- 在某些系统上,如果
stacksize
不是系统页面大小的倍数,pthread_attr_setstacksize()
可能会失败,并显示错误EINVAL
查询<a hre
f="https://http://coding3min.com/808.html"> linux 报错码含义, 得知错误码 22
果然和 man
手册中说的一致,是参数有问题。
![e18a9703dcb7d0993a70a48831b314e5.png](https://i-blog.csdnimg.cn/blog_migrate/df14ba82a54b197cbd0e873d1e9d1f59.png)
第一次尝试:扩大线程栈到上面说的 16384
,但还是报错
![ddfe935a4f2c8575edc053b220647e66.png](https://i-blog.csdnimg.cn/blog_migrate/10952c0c082d6308310e4b508fb2ac2f.jpeg)
根据经验,查看最小页大小,发现是 16k
, 而 x86
架构是 4K
,原来用的 20K
是不对齐的,怪不得创建不出来线程。
![35ba2beb3d46282d7e37fd26a0b37515.png](https://i-blog.csdnimg.cn/blog_migrate/544650915ab89bbc1bfabb0ad04dc738.png)
依次尝试, 最终发现 10*16K
子线程成功创建。
但是不准确,按其说法,应该是设置 PAGESIZE
的整数倍都行,怀疑其对最小值有要求。 c++
的头文件在 /usr/include
目录下面, PTHREAD_STACK_MIN
是一个常量,估计里面会有定义,尝试查找
$ grep -rl PTHREAD_STACK_MIN *
bits/local_lim.h
pthread.h
还真让我找到了, 根据英文注释,至少要两个 64K
作为线程栈,才能跑起一个线程。
![7735c3fdee1b89e2b4c09e226be7c9c5.png](https://i-blog.csdnimg.cn/blog_migrate/bce1ff3ade681198e2b7fe8cc9ed68d4.png)
至此问题解决。
部分线程卡住
我发现程序虽然正常运行,但是部分功能不正常,经过查看日志发现,有一个线程只执行了一半就卡住了。
经过查看日志可以定位出是哪个线程卡住,如果从日志看不出来也没关系。可以使用 pstack 进程号
看一些进程堆栈。
查看进程 pid
ps -ef |grep 进程名
使用 gdb
查看是否出现问题,两个重要命令
gdb attach {pid} #查看正在运行程序的栈
info thread #进入以后使用,查看线程信息
找到错误位置,出现了 fgets()
和 read()
函数,怀疑是此处出现问题。
![b9f748653b690981af78b3580935d8e7.png](https://i-blog.csdnimg.cn/blog_migrate/32ff4f2ed6604f7b331bcc0cbd0ffd13.jpeg)
![63423fadb87d316f0db1198dfa298ba6.png](https://i-blog.csdnimg.cn/blog_migrate/83e691e199c86dccdf080b56c8b667d7.png)
怀疑 1: _LINE_LENGTH 1024
长度太短,接受命令返回值后超过了数组本身的长度,覆盖了未知的内存。
这种情况我以前遇到过,表现应该是程序直接就崩溃了。
怀疑 2:执行命令的时候卡了,导致后面的程序没有执行。
根据 gdb
打印出来的参数,执行 linux
命令进行测试,果然是卡在这了!
再次使用 pstree -p {pid}
查看,确实主线程,调用了 linux
命令卡住。
![47be4e155de538fa65f63ca7f283df81.png](https://i-blog.csdnimg.cn/blog_migrate/4e97d15de39a0a697ea6efe4ebe38b01.jpeg)
接下来解决卡命令的问题
解决 1:加 timeout
处理空返回。下面是示例命令,并不是我使用的命令。
timeout 5 ls -al
代表超过 5 秒返回。
解决 2:定位为什么这个 linux
命令会卡住。
strace ls -al
直到解决为止。这就是今晚我加班到 10 点 30 解决的问题,我又用了一个小时总结下整个过程备忘,希望对你也有帮助。