一、进程和线程进程和线程是什么勿需多言。在面试或者稍微复杂的程序开发中都是不可避免的。什么进程是资源最小的分配单元线程是运行调度的最小单元。相信只要大家明白其中的意思如何表述就看具体的侧重的角度了。但不管如何描述进程和线程都会有一个至关重要的问题也就是实际开发经常遇到的一个问题如何对进程和线程进行管理特别是很多情况对进程和线程的运行状态或者运行异常需要处理。二、Linux下对进程和线程的管理控制在不同的平台上可能相关的处理的手段有所不同。但基本原理都差不多。本文将以Linux平台为基础进行相关的问题分析。进程的管理在Linux平台上原来是只有进程的概念的。而进程既是资源分析的最小单元也是任务运行的最小单元Posix库才正式引入了线程当然前面也有轻量级进程的线程但在内核中始终是轻量级进程的概念。进程很重每个进程的调度和运行都占用相当多的资源这也是为什么现代的操作系统向线程甚至协程发展的原因。进程有自己唯一的标识ID以此ID获取句柄就可对进程进行全面的管理。在内核中sched.c和sched.h文件中支持了对进程控制管理的大部分相关的数据封装和函数支持。包括创建、执行、终止等状态的管理以及相关状态调度。在前面的内核分析的相关文章中有对此部分的详细说明但可能相关的代码已经较老可自行下载最新的内核相关源码进行对照比较分析。在Linux的终端内可以使用ps、top、pstree命令或相关的资源管理软件对相关的线程的状态等进行查看和管理也可能通过kill等命令对其进行杀死也可以使用nice或bg/fg等调整其优先级和前后台作业。线程的管理线程是包含在进程之中的也可以理解进程是线程的容器。是真正执行任务的单元。线程有自己的运行状态这其中包括寄存器和栈是否还记得线程默认的栈的大小等。同一进程的线程可以互相访问这也是常见的线程同步的技术点所在。与进程一样每个线程都有自己的线程ID通过这个唯一的ID可以获取线程的句柄。通过此句柄就可以实现对线程的管理和相关状态的获取。两样在源码sched.c和sched.h文件中有对线程管理的相关数据结构和函数处理有兴趣的可以深入分析一下。而在上层所谓的各种运行状态和接口其实都是直接或间接的对其封装和引用。在Linux的终端内可以使用ps -eLf使用相关的参数还可以查看更多的线程状态或相关的软件对线程的状态等进行监控。另外Htop也是一个不错的终端命令对线程管理的更清晰明确。也可能pidstat这个工具来查看指定的线程的应用状态。当然和进程一样也可以使用相关相同的命令来杀死和操作前后台作业及优先级下面看几个常用的命令ps -ef|grep 进程名 #可以使用通配符 ps -aux|grep 进程名 ps -eo ruser,pid,ppid,lwp,psr,args -L | grep PID #查看线程在哪个CPU上运行。 ps -Lf PID #显示进程ID、线程ID和线程数量(NLWP) pidstat -t -p PID #监控特定线程三、相关的API分析在Linux平台上提供了对进程和线程操作的一系列的API接口。主要有进程和线程属性的接口如进程的ID获取接口getpid()会话管理getsid()和setsid()以及进程组管理getpgid()和setpgid()线程的ID获取接口gettid()。由于在Linux内核中线程和进程几乎可以看成一回事所以其专有的接口较少。进程和线程信息的接口进程和线程信息接口的查询相对较少主要还是通过文件系统进行处理。这会在下面的相关内容中进行分析。当然也可以借助其它一些库如procps来达到相关的目的进程线程应用的接口进程相关的接口有fork(),clone()、nice(),sched_*一系列调度函数接口以及ptrace()进程跟踪和调试接口。而线程中由大多数与进程相同但也提供了一些具体如CPU亲和性sched_setaffinity()和 sched_getaffinity()等接口四、详细信息的获取虽然说上面的接口可以覆盖大多数的应用场景但在一些细节控制上其实Linux提供了更丰富的机制。在前面的学习中知道Linux中一切皆文件那么其对进程和线程的管理以及状态控制都可以通过文件进行。在Linux系统中可以通过下面的方式获取相关进程和线程的属性和状态进程属性和状态进程的相关内容管理在/proc//stat(机器解析的进程统计数据用于ps等工具)、proc//status信息更完整供人直接查看的进程状态和内存等信息以及/proc/self/status它指向当前进程的proc//status。这里面的内容很全面而且很好理解就不再贴上来占用空间和详细分析说明了线程属性和状态同样也可以在/proc下获取相关线程的内容/proc/[pid]/task/[tid]/status获取指定线程的状态信息、/proc/thread-self指向目前正在访问/proc的线程自身的信息与 /proc/tid/等同于/proc//task//即直接通过tid进行访问。同样不再将具体的内容复制上来有兴趣可以自行去查看一下通过上述的文件内容读取可以获取进程和线程的属性如ID、名称、状态以及内存占用大小、CPU占用率及IO状态等等。也就是说在Linux中关于进程和线程相关的内容都在/proc目录下大家可以手工的打开相关的文件来查看一下这样就可以更好的理解相关的详细内容。五、例程下面给出一个线程监控的例子#include cstring #include dirent.h #include filesystem #include fstream #include iostream #include string #include tuple constexpr std::string_view fs_path_proc(/proc/); std::tuplebool, pid_t ActivityMonitor::getAppPidFromProcfsByName(const std::string_view appName) { bool ret false; pid_t pid -1; DIR *pDirStream{nullptr}; struct dirent *pDirEntry{nullptr}; // open /proc pDirStream opendir(fs_path_proc.data()); if (!pDirStream) { LOG(ERROR) opendir err,ret: ret; return {ret, pid}; } // traverse all directories under /proc while ((pDirEntry readdir(pDirStream)) ! nullptr) { // ignore non numeric values if (pDirEntry-d_type ! DT_DIR || !isdigit(pDirEntry-d_name[0])) { continue; } std::string cmdPath fs_path_proc.data() std::string(pDirEntry-d_name) /cmdline; std::ifstream cmdFile(cmdPath); std::string cmdLineStr; // read info std::getline(cmdFile, cmdLineStr); cmdFile.close(); // find process name if (cmdLineStr.find(appName) ! std::string::npos) { pid std::stoi(pDirEntry-d_name); ret true; break; } } closedir(pDirStream); return {ret, pid}; }上面的代码只是给出了/proc路径下通过名字进行获取ID的最终函数没有给出全部的监控过程。大家有兴趣可以自行扩展一下。六、总结通过上面的分析可以知识在Linux平台上可以把对进程和线程的管理分为三层即内核层负责底层的管理操作能力用户态层通过各种库或上层应用接口提供了对进线程的系统调用和管理最后是监控管理层通过文件系统或相关库为上层提供了进程和线程的整体状态的监控能力。在明白了上述的情况后开发者就可以有针对性的根据实际的需求来确定使用哪种机制来实现其目标。C编程实践—进程信息管理控制一、进程和线程进程和线程是什么勿需多言。在面试或者稍微复杂的程序开发中都是不可避免的。什么进程是资源最小的分配单元线程是运行调度的最小单元。相信只要大家明白其中的意思如何表述就看具体的侧重的角度了。但不管如何描述进程和线程都会有一个至关重要的问题也就是实际开发经常遇到的一个问题如何对进程和线程进行管理特别是很多情况对进程和线程的运行状态或者运行异常需要处理。二、Linux下对进程和线程的管理控制在不同的平台上可能相关的处理的手段有所不同。但基本原理都差不多。本文将以Linux平台为基础进行相关的问题分析。进程的管理在Linux平台上原来是只有进程的概念的。而进程既是资源分析的最小单元也是任务运行的最小单元Posix库才正式引入了线程当然前面也有轻量级进程的线程但在内核中始终是轻量级进程的概念。进程很重每个进程的调度和运行都占用相当多的资源这也是为什么现代的操作系统向线程甚至协程发展的原因。进程有自己唯一的标识ID以此ID获取句柄就可对进程进行全面的管理。在内核中sched.c和sched.h文件中支持了对进程控制管理的大部分相关的数据封装和函数支持。包括创建、执行、终止等状态的管理以及相关状态调度。在前面的内核分析的相关文章中有对此部分的详细说明但可能相关的代码已经较老可自行下载最新的内核相关源码进行对照比较分析。在Linux的终端内可以使用ps、top、pstree命令或相关的资源管理软件对相关的线程的状态等进行查看和管理也可能通过kill等命令对其进行杀死也可以使用nice或bg/fg等调整其优先级和前后台作业。线程的管理线程是包含在进程之中的也可以理解进程是线程的容器。是真正执行任务的单元。线程有自己的运行状态这其中包括寄存器和栈是否还记得线程默认的栈的大小等。同一进程的线程可以互相访问这也是常见的线程同步的技术点所在。与进程一样每个线程都有自己的线程ID通过这个唯一的ID可以获取线程的句柄。通过此句柄就可以实现对线程的管理和相关状态的获取。两样在源码sched.c和sched.h文件中有对线程管理的相关数据结构和函数处理有兴趣的可以深入分析一下。而在上层所谓的各种运行状态和接口其实都是直接或间接的对其封装和引用。在Linux的终端内可以使用ps -eLf使用相关的参数还可以查看更多的线程状态或相关的软件对线程的状态等进行监控。另外Htop也是一个不错的终端命令对线程管理的更清晰明确。也可能pidstat这个工具来查看指定的线程的应用状态。当然和进程一样也可以使用相关相同的命令来杀死和操作前后台作业及优先级下面看几个常用的命令ps -ef|grep 进程名 #可以使用通配符 ps -aux|grep 进程名 ps -eo ruser,pid,ppid,lwp,psr,args -L | grep PID #查看线程在哪个CPU上运行。 ps -Lf PID #显示进程ID、线程ID和线程数量(NLWP) pidstat -t -p PID #监控特定线程三、相关的API分析在Linux平台上提供了对进程和线程操作的一系列的API接口。主要有进程和线程属性的接口如进程的ID获取接口getpid()会话管理getsid()和setsid()以及进程组管理getpgid()和setpgid()线程的ID获取接口gettid()。由于在Linux内核中线程和进程几乎可以看成一回事所以其专有的接口较少。进程和线程信息的接口进程和线程信息接口的查询相对较少主要还是通过文件系统进行处理。这会在下面的相关内容中进行分析。当然也可以借助其它一些库如procps来达到相关的目的进程线程应用的接口进程相关的接口有fork(),clone()、nice(),sched_*一系列调度函数接口以及ptrace()进程跟踪和调试接口。而线程中由大多数与进程相同但也提供了一些具体如CPU亲和性sched_setaffinity()和 sched_getaffinity()等接口四、详细信息的获取虽然说上面的接口可以覆盖大多数的应用场景但在一些细节控制上其实Linux提供了更丰富的机制。在前面的学习中知道Linux中一切皆文件那么其对进程和线程的管理以及状态控制都可以通过文件进行。在Linux系统中可以通过下面的方式获取相关进程和线程的属性和状态进程属性和状态进程的相关内容管理在/proc//stat(机器解析的进程统计数据用于ps等工具)、proc//status信息更完整供人直接查看的进程状态和内存等信息以及/proc/self/status它指向当前进程的proc//status。这里面的内容很全面而且很好理解就不再贴上来占用空间和详细分析说明了线程属性和状态同样也可以在/proc下获取相关线程的内容/proc/[pid]/task/[tid]/status获取指定线程的状态信息、/proc/thread-self指向目前正在访问/proc的线程自身的信息与 /proc/tid/等同于/proc//task//即直接通过tid进行访问。同样不再将具体的内容复制上来有兴趣可以自行去查看一下通过上述的文件内容读取可以获取进程和线程的属性如ID、名称、状态以及内存占用大小、CPU占用率及IO状态等等。也就是说在Linux中关于进程和线程相关的内容都在/proc目录下大家可以手工的打开相关的文件来查看一下这样就可以更好的理解相关的详细内容。五、例程下面给出一个线程监控的例子#includecstring#includedirent.h#includefilesystem#includefstream#includeiostream#includestring#includetupleconstexpr std::string_viewfs_path_proc(/proc/);std::tuplebool,pid_tActivityMonitor::getAppPidFromProcfsByName(conststd::string_view appName){bool retfalse;pid_tpid-1;DIR*pDirStream{nullptr};structdirent*pDirEntry{nullptr};// open /procpDirStreamopendir(fs_path_proc.data());if(!pDirStream){LOG(ERROR)opendir err,ret:ret;return{ret,pid};}// traverse all directories under /procwhile((pDirEntryreaddir(pDirStream))!nullptr){// ignore non numeric valuesif(pDirEntry-d_type!DT_DIR||!isdigit(pDirEntry-d_name[0])){continue;}std::string cmdPathfs_path_proc.data()std::string(pDirEntry-d_name)/cmdline;std::ifstreamcmdFile(cmdPath);std::string cmdLineStr;// read infostd::getline(cmdFile,cmdLineStr);cmdFile.close();// find process nameif(cmdLineStr.find(appName)!std::string::npos){pidstd::stoi(pDirEntry-d_name);rettrue;break;}}closedir(pDirStream);return{ret,pid};}上面的代码只是给出了/proc路径下通过名字进行获取ID的最终函数没有给出全部的监控过程。大家有兴趣可以自行扩展一下。六、总结通过上面的分析可以知识在Linux平台上可以把对进程和线程的管理分为三层即内核层负责底层的管理操作能力用户态层通过各种库或上层应用接口提供了对进线程的系统调用和管理最后是监控管理层通过文件系统或相关库为上层提供了进程和线程的整体状态的监控能力。在明白了上述的情况后开发者就可以有针对性的根据实际的需求来确定使用哪种机制来实现其目标。