概念 进程和程序比较 进程内容 进程控制块 进程类型 进程状态 查看进程信息 执行命令如下: 具体命令参数信息如下:-D:不可被唤醒的睡眠状态,通常用于 I/O 情况。 -R:该进程正在运行。 -S:该进程处于睡眠状态,可被唤醒。 -T:停止状态,可能是在后台暂停或进程处于除错状态。 -W:内存交互状态(从 2.6 内核开始无效)。 -X:死掉的进程(应该不会出现)。 -Z:僵尸进程。进程已经中止,但是部分程序还在内存当中。 -<:高优先级(以下状态在 BSD 格式中出现)。 -N:低优先级。 -L:被锁入内存。 -s:包含子进程。 -l:多线程(小写 L)。 -+:位于后台。  实时查看进程命令如下: 改变进程优先级 设置优先级案例如下: 改变优先级案例如下: 进程相关命令 案例代码如下: 子进程概念 子进程创建-fork 创建子进程案例如下: 父子进程 父子进程案例如下: 运行如下: 通过父进程号看出子进程和父进程 在用kill -9 杀死父进程,然后可以发现子进程的父进程PPID变成1,也就是init进程中,然后另一个终端ctrl + c结束不掉,说明以及变为后台进程了 一个父进程拥有五个子进程,代码如下:  运行结果如下: 解决办法如下: 进程结束-exit/_exit 案例如下: 执行如下: 进程回收-wait 例子代码如下: 执行后使用ps查看进程的状态,看是否由僵尸进程,也就是判断exit是否收回子进程,如下: 查看注释wait那两行后的ps状态如下: 进程回收-waitpid 案例如下: 有一个案例要注意下如下: 执行如下: 修改后代码代码如下: 修改如下: 进程调用exec函数族执行某个程序(exec test可以执行第三方程序)
进程当前内容被指定的程序替换(当你执行exec 后面的程序,那么exec当前程序后面的部分都会被替换)
实现让父子进程执行不同的程序(shell就是执行下面的步骤,可以不被替换)
* 父进程创建子进程
* 子进程调用exec函数族
* 父进程不受影响
进程-execl/execlp成功时执行指定的程序;失败时返回EOF path 执行的程序名称,包含路径 arg… 传递给执行的程序的参数列表 file 执行的程序的名称,在PATH中查找  案例演示: 执行如下: 也可以改为execlp函数调用如下: 执行结果如下: 进程-execv 函数代码如下: 进程-system代码使用如下: 概念:
守护进程又叫精灵进程(Daemon Process),它是一个生存期较长的进程,通常独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。
特点:
* 始终在后台运行,独立于任何终端,周期性的执行某种任务或等待处理特定事件。(前台就是类似./test,而后台进程则是./test &)
* 它是个特殊的孤儿进程,这种进程脱离终端,为什么要脱离终端呢?之所以脱离于终端是为了避免进程被任何终端所产生的信息所打断,其在执行过程中的信息也不在任何终端上显示。由于在 Linux 中,每一个系统与用户进行交流的界面称为终端,每一个从此终端开始运行的进程都会依附于这个终端,这个终端就称为这些进程的控制终端,当控制终端被关闭时,相应的进程都会自动关闭。
进程组:进程集合,每次进程组有一个组长,其进程ID就是该进程组的ID
会话:进程组集合,每个会话有一个组长,其进程ID就是该会话组ID
控制终端:每个会话可以有一个单独的控制终端,与控制终端连接的Leader就是控制进程
举例: 首先,创建子进程,父进程退出,子进程变成孤儿进程,被init进程收养,前面都有提到,然后子进程在后台运行
其次,子进程创建新会话,通过调用setsid函数,来成为新会话组长,子进程脱离原先的终端
然后,改变当前工作目录,调用chdir函数,但不是必须的,根据你一开始的目录是否稳定的来决定,守护进程一直在后台运行,所以工作目录不能被删除
之后,重设文件权限掩码,使用umask(0)将文件权限掩码设置为0,这一步也不是必须的
最后,关闭打开的文件描述符,使用close函数关闭所有从父进程继承的打开文件,而且守护进程已脱离终端,所以stdin/stdout/stderr无法再使用
上述第一步父进程退出相关代码的实现如下: 使用nohup函数代码如下: 执行如下代码: 创建子进程会话代码 执行下: 下面的几步可选的,做不做都行,下面将演示下 进入GDB模式: 调试命令如下: 其中关键的部分就是如何进入到子进程中的函数命令如下: 如何同时跟踪父进程和子进程如下: 通常线程指的是共享相同地址空间的多个任务 使用多线程的好处就是大大提高了任务切换的效率,避免了额外的TLB&cache的刷新 一个进程中的多个线程共享以下资源: 每个线程私有的资源包括: pthread线程库中提供了如下基本操作 同步和互斥机制 线程创建 具体操作代码如下: 上述编译错误分析:)’ but argument is of type ‘int * ( )(char )’  )(void ) ,实际的代码是int * ( )(char ) )testThread,NULL);  线程结束-phread_exit 代码如下: 线程查看tid函数 如何使用如下,直接调用函数即可,注意pthread_t为lu类型,无符号长整型: 执行如下: 线程的参数传递函数调用如下: 执行如下:arg);类型指针不能直接用 取值(arg),因为编译不知道数据类型。 取值 比如: (int *)arg 
  通过地址传递参数,注意类型的转换 值传递,这时候编译器会告警,需要程序员自己保证数据长度正确。这个方式见如下:  创建多个线程 执行如下: 线程的回收:’ [-Wformat=] )retv 使用线程的分离: 线程的取消: 函数介绍(这两个函数必须成对使用)被pthread_cancel取消掉。 执行pthread_exit 非0参数执行pthread_cleanup_pop() 必须成对使用,即使pthread_cleanup_pop不会被执行到也必须写上,否则编译错误。 pthread_cleanup_pop()被执行且参数为0,pthread_cleanup_push回调函数routine不会被执行. pthread_cleanup_push 和pthread_cleanup_pop可以写多对,routine执行顺序正好相反 线程内的return 可以结束线程,也可以给pthread_join返回值,但不能触发pthread_cleanup_push里面的回调函数,所以我们结束线程尽量使用pthread_exit退出线程。  代码如下: 执行后发现编译出错,原因是这两个函数需要成对使用,错误如下: 如何修改代码如下: pthread_cleanup_pop函数的用法 执行如下: