1、程序:一堆未被执行的代码,他是静态的,程序是不会消耗CPU资源,与内存资源,但占用硬盘空间。 所以当一个计算机掉电时,程序不会丢失。
2、进程:正在执行的代码,他是动态的, 会消耗内存资源,与CPU资源,当进程结束时,这些资源就会被释放。
3、所有的进程都由父进程生产出来。(除了init(systemd)进程,没有父亲)
4、进程的命令:
查看当前系统中的所有进程:
ps -e
查看进程的家族关系:
pstree
杀死进程:
kill 进程号
killall 进程名
5、进程的状态(活的):
就绪态:当一个进程被创建出来后,但还未获得时间片时,该进程就为就绪态。
执行态:获得时间片,CPU的使用权
睡眠态:用户调用sleep函数,usleep函数 (睡眠函数)。
暂停态:用户发送暂停信号(kill -19 进程ID)
僵尸态:进程死亡就会进入到僵尸态 (主函数调用return ,调用exit,被信号杀死...)
PS:进程是系统分配资源的最小单位!!!(分配内存空间!)
5、进程的创建:
#include <sys/types.h>
#include <unistd.h>
pid_t fork(void);
返回值: 大于0的是子进程的PID号 (父进程返回的)
等于0 (子进程返回的)
(子进程的所有资源都是从父亲进程中拿过来的!!!)
6、子进程拿到父进程的资源有如下:
1.用户ID和组ID
2.所有的环境变量
3.进程组ID 会话ID
4.当前的工作路径
5.打开的文件描述符与文件指针
6.信号函数
7.整个内存空间
不拷贝的如下:
1.进程PID号
2.记录锁
3.暂停信号
7、获取进程的ID号函数:
#include <sys/types.h>
#include <unistd.h>
pid_t getpid(void); //获取当前的进程ID号
pid_t getppid(void); //获取父亲进程的ID号
8、进程的等待:
#include <sys/types.h>
#include <sys/wait.h>
//随便等待一个进程结束 (谁最先结束就回收谁的资源)
pid_t wait(int *wstatus);
参数一:退出状态
返回值:成功 退出进程的PID号
失败 -1
//等待某一子进程退出
pid_t waitpid(pid_t pid, int *wstatus, int options);
参数一:需要等待的进程PID号
参数二:退出状态
参数三:属性
阻塞: 0 (一直停留在哪里直到有人退出为止)
非阻塞: WNOHANG (去等待一下,等不了就走)
//wstatus 进程的退出状态值
WIFEXITED(wstatus) //判断是否为正常退出
WEXITSTATUS(wstatus) //获取正常退出的值 (return 的值) 不能超过8位 最大为255
WIFSIGNALED(wstatus) //被信号杀死
WTERMSIG(wstatus) //获取杀死他的信号值
WIFSTOPPED(wstatus) //被信号暂停
WSTOPSIG(wstatus)//获取暂停的值
9、进程的退出函数
#include <unistd.h>
//只要代码中调用该函数,进程就立马退出
void exit(int status); //在退出的时候,会帮我们回收资源,例如清空缓存区
void _exit(int status);//在退出的时候,不会做任何事情
注意:int status参数与return 后的值一样 !!!
父亲进程死亡了,子进程不会死亡,(他就变成了孤儿进程,孤儿进程由系统进程回收!)。
10、进程的“脱胎换骨”
使用execl族函数使子进程继承父亲的资源,并自己独立执行其他程序。
//获取当前进程的环境变量
#include <stdlib.h>
char *getenv(char *envvar);
参数:需要获取的环境变量
#include <unistd.h>
功能:让子进程去执行其他程序。
int execl(const char *path, const char *arg, ... /* (char *) NULL */);
参数一:可执行文件的路径 (绝对路径)
参数二:传递给可执行程序的参数,(int argc,char *argv[])
参数三:必须为NULL
失败返回:-1;
使用例子:
execl("/mnt/hgfs/main","main","???",NULL);
//??? -》用户需要传递给进程的参数
int execv(const char *path, const char *argv[]); //与上述功能一致,只不过这个传递的是数组指针
参数一:可执行文件的路径 (绝对路径)
参数二:传递给任务函数的参数 (字符串指针数组,注意该数组末尾必须为NULL)
int execle(const char *path, const char *arg, ...
/*, (char *) NULL, char * const envp[] */); //可以附加环境变量
//自动传递主进程的环境变量给子进程使用 (带环境的,可以不用写绝对路径)
int execlp(const char *file, const char *arg, ... /* (char *) NULL */);
int execvp(const char *file, char *const argv[]);
int execvpe(const char *file, char *const argv[], char *const envp[]);
11、system函数的使用
#include <stdlib.h>
int system(const char *command);
参数一:需要执行的命令
返回值: 0 执行的命令为NULL
-1 创建子进程失败
其他值 退出状态
PS:system函数他会去创建一个进程调用我们的命令
//调用system创建进程执行命令
system("ls -al");
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main()
{
//需要带等待的哪一个进程
int i=0;
//创建一个子进程
pid_t pid = fork();
if(pid == 0) //子进程1
{
printf("子进程=%d\n",getpid());
sleep(1);
}
if(pid > 0)
{
printf("父进程退出=%d\n",getpid());
}
printf("等待子进程结束\n");
int stat;
//wait(&stat);//随便等待一个最先结束的
printf("wait_pid=%d\n",pid);
waitpid(pid,&stat,0); //等待PID号的子进程结束
printf("all proc end\n");
}
运行效果如下:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int quit() //函数里面退出进程 就可以调用exit
{
printf("退出进程\n");
//exit(0);//调用进程退出函数
_exit(0);
printf("返回-1\n");
return -1;
}
int main()
{
int i=0;
while(1)
{
printf("i=%d\n",i++);
if(i==5)
{
quit();
//return 0; //退出
}
sleep(1);
}
}
测试效果如下: