线程测试程序
#include <iostream>
#include <thread>
#include <cstring>
#include <unistd.h>
#include <mutex>
using namespace std;
#define LEN 2
int num = 0;
std::mutex mt;
void run() {
std::cout << "count = " << num << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(1));
mt.lock();
num-=1;
mt.unlock();
}
int main() {
while (true){
while (num < LEN){
mt.lock();
num+=1;
mt.unlock();
std::thread t(run); //
t.detach();
}
}
return 0;
}
分析:在上面的程序中创建了两个线程,程序执行起来,main函数所在的程序为主线程,在这个主线程中有两个新的线程运行
ps:这个程序的名字叫做 hlog
如何命令行查询
1、查询当前程序的进程ID
# 查看当前程序的进程ID,是 89588 , 23653 是父进程ID
$ ps -eaf |grep hlog|grep -v grep
oceanst+ 89588 23653 99 15:43 ? 00:04:36 /home/oceanstar/CLionProjects/hlog/cmake-build-debug/hlog
# 或者
$ ps -aux |grep hlog|grep -v grep
oceanst+ 89588 99.8 0.0 39432 1220 ? Rl 15:43 7:15 /home/oceanstar/CLionProjects/hlog/cmake-build-debug/hlog
2、 查看当前线程开启的进程数:
$ ps -eo ruser,pid,ppid,lwp,psr,args -L | grep hlog
oceanst+ 89588 23653 89588 1 /home/oceanstar/CLionProjects/hlog/cmake-build-debug/hlog # 主
oceanst+ 89588 23653 93099 0 /home/oceanstar/CLionProjects/hlog/cmake-build-debug/hlog # 从
oceanst+ 89588 23653 93100 3 /home/oceanstar/CLionProjects/hlog/cmake-build-debug/hlog # 从
oceanst+ 93102 25485 93102 2 grep --color=auto hlog # 命令本身的线程
其中,每一列依次为:用户ID,进程ID,父进程ID,线程ID,运行该线程的CPU的序号,命令行参数(包括命令本身)。
# 查看status文件
$ cat /proc/89588/status
Name: hlog # 程序名称
State: R (running) # 运行状态
Pid: 89588 # 进程ID
PPid: 23653 # 父进程ID
Threads: 3 # 当前线程数【包括主线程】
# 或者查看sched文件
$ cat /proc/89588/sched
hlog (89588, #threads: 3) 第一行就指出了pid和总线程数。
-------------------------------------------------------------------
se.exec_start : 15487517.919034
查看线程的具体情况:task下是以线程id 值命名的目录,可以使用ls |wc 统计出的值和上面两种方式查出的结果一样。进入各线程id的目录,可以查看具体线程的资源信息。
$ ls /proc/89588/task
89588 94464 94465
注:上面查看文件的方法,主要是对单进程的线程统计。如像统计apache、nginx、zabbix这类程序会同时开启N个进程。如果要统计这类程序的线程数,就是所有进程下的线程数的之和。
3、查看主线程和新线程的关系
$ pstree -p 89588
hlog(89588)─┬─{hlog}(91010)
└─{hlog}(91011)
4、线程栈结构的查看
pstack命令一般情况下用不到,其是一个栈跟踪的命令 。一般和 core dump和程序分析相关,也可以获取线程的详细信息。如:
$ pstack 线程ID
5、利用gdb查看线程信息
- 将进程附加到gdb调试器当中,查看是否创建了新线程:gdb attach 主线程ID
$ gdb attach 主线程ID
*查询线程的一些信息
//1.查看进程:info inferiors
//2.查看线程:info threads
//3.查看线程栈结构:bt
//4.切换线程:thread n(n代表第几个线程)
* info threads: 显示当前可调试的所有线程,每个线程有一个GDB为其分配的ID,后面操作线程的时候会用到这个ID 。前面的有*的是当前调试的线程
* thread ID: 切换为指定ID的线程
//1.设置断点:break 行号/函数名
//2.查看断点:info b
1.继续使某一线程运行:thread apply 1-n(第几个线程)n
2.重新启动陈故乡运行到断点处:r
**** 没有看完 ****
gdb调试
list
- list命令显示多行源代码,从上次的位置开始显示,默认情况下,一次显示10行,第一次使用时,从代码起始位置显示
76
77 NET_PARAM stuNetParam = {0};
78 stuNetParam.nGetDevInfoTime = 3000;
79 CLIENT_SetNetworkParam(&stuNetParam);
80 }
81 int main(int argc, char *argv[])
82 {
83 // LOG(INFO) << "=================================start========================================";
84 // init_HIK();
85 init_Dahua();
- list n显示已第n行未中心的10行代码
(gdb) list 15
10
11 INITIALIZE_EASYLOGGINGPP
12 map<string , TJKJ_PTZ_CONFIGS> dahua_camera_picture;
13 std::vector<TJKJ_PTZ_CONFIGS> success_camera_infos;
14 int run_number;
15 int this_camera_id = 0;
16 int end_success = 0;
17 time_t start_time;
18 time_t end_time;
19
- list functionname显示以functionname的函数为中心的10行代码
(gdb) list Init_db
151
152 NET_DVR_Cleanup();
153 return 0;
154 }
155
156 int Init_db(){
157 std::vector<TJKJ_PTZ_CONFIGS> Camera_Vector;
158 int init_mysql_statue = query_mysql_camera(Camera_Vector);
159 if (init_mysql_statue == 0){
160 LOG(INFO) << "db connection fail, exit";
list - 显示刚才打印过的源代码之前的代码
(gdb) list -
151
152 NET_DVR_Cleanup();
153 return 0;
154 }
155
156 int Init_db(){
157 std::vector<TJKJ_PTZ_CONFIGS> Camera_Vector;
158 int init_mysql_statue = query_mysql_camera(Camera_Vector);
159 if (init_mysql_statue == 0){
160 LOG(INFO) << "db connection fail, exit";
break