前言
进程和线程的广泛意义是什么?
进程是计算机中运行的程序的实例。它具有独立的内存空间和资源,是操作系统分配和管理资源的基本单位。每个进程都拥有独立的地址空间、全局变量和文件打开等资源,进程之间相互独立。进程之间通常通过进程间通信(IPC)机制进行数据交互。
线程是进程中的一个执行单元。一个进程可以包含多个线程,这些线程共享进程的地址空间和资源,可以同时执行不同的代码路径。线程之间可以通过共享内存进行数据交换,因为它们可以访问相同的全局变量和堆内存。
一、进程基础
1.进程概念
进程是一个独立的可调度的任务
(1)进程是一个抽象实体。当系统在执行某个程序时,分配和释放的各种资源
(2)进程是一个程序的一次执行的过程
进程和程序的区别
程序是静态的,它是一些保存在磁盘上的指令的有序集合,没有任何执行的概念
进程是一个动态的概念,它是程序执行的过程,包括创建、调度和消亡
进程是程序执行和资源管理的最小单位
2.进程特征
动态性 ----程序一次运行过程
并发性 ----可以同时运行多个进程
独立性 ----每个进程在各自独立的虚拟内存中运行
异步性 ----多个运行的进程之间相互没有关系
3.进程状态(如图清晰可见)
4,进程的标识
(1)主要的进程标识
进程号(Process Identity Number,PID)
父进程号(Parent Process ID,PPID)
(2)PID唯一地标识一个进程。可以通过以下两个函数获得:
pid_t getpid(void) //获取进程ID
pit_t getppid(void) //获取父进程ID
实例代码如下:
int main(void) { printf("pid = %d\n",getpid()); printf("ppid = %d\n",getppid()); return 0; }
在终端运行的结果以及ps命令作用结果如下:
5.进程的种类
(1)交互进程:
该类进程是由shell控制和运行的。交互进程既可以在前台运行,也可以在后台运行。
(2)批处理进程:
该类进程不属于某个终端,它被提交到一个队列中以便顺序执行。
实例shell脚本程序如下:
终端输入命令如下:
touch test.sh chmod a+x test.sh test.sh内容如下: ls touch 1.txt 2.txt 3.txt ls / cat fork1.c
运行shell脚本文件如下:
peter@ubuntu:~/2308/proc/day01_code$ ./test.sh 1.txt 3.txt exit.c fork2.c main.c myproc.c test.sh wait.c waitpid.c 2.txt exec.c fork1.c getpid.c Makefile test.c wait waitpid bin cdrom etc initrd.img lib lost+found mnt proc run snap swapfile tftpboot u sr vmlinuz boot dev home initrd.img.old lib64 media opt root sbin srv sys tmp var vmlinuz.old #include <stdio.h> #include <sys/types.h> #include <unistd.h> int main(void) { fork(); printf("hello world\n"); return 0; }
(3)守护进程:
该类进程在后台运行。它一般在Linux启动时开始执行,系统关闭时才结束
二、进程API
1.创建子进程
pid_t fork(void);
fork调用过程:
1,映射新的进程虚拟空间,该进程称为子进程。
2,将父进程的各个数据段中的数据拷贝到子进程中
3,父子进程共享代码段
4,fork()调用过程返回两个值:
第一个值:给父进程返回子进程的ID号
第二个值:给子进程返回0
调用失败返回:-1
5,父子进程,从fork()调用的下一条语句同时运行
实例代码如下:
void fun(void) { int i; for(i = 0 ; i < 7; i++){ printf("我是子进程,我要好好学习\n"); sleep(1); } } int main(void) { int i; pid_t pid; if((pid = fork()) < 0){ perror("fork"); exit(1); }else if(!pid) fun(); else for(i = 0 ; i < 7; i++){ printf("我是父进程,我要努力赚钱\n"); sleep(1); } return 0; }
2.exec函数族
//加载另一个程序在进程的空间中执行 #include <unistd.h> extern char **environ; int execl(const char *path, const char *arg, ... /* (char *) NULL */); int execlp(const char *file, const char *arg,.../* (char *) NULL */); int execle(const char *path, const char *arg,../*, (char *) NULL,char * const envp[] */); int execv(const char *path, char *const argv[]); int execvp(const char *file, char *const argv[]); int execve(const char *path, char *const argv[], char *const envp[]);
函数族讲解图如下所示:
实例代码如下所示:
int main(void) { int i; pid_t pid; if((pid = fork()) < 0){ perror("fork"); exit(1); }else if(!pid){ //子进程:执行另一个程序,如:ls #if 0 //execl("/bin/ls","ls","-l",NULL); //execlp("ls","ls","-l",NULL); char * arg[] = {"ls","-l",NULL}; //execv("/bin/ls",arg); execvp("ls",arg); #else //execl("/home/peter/2308/proc/day01_code/myproc","./myproc",NULL); char * env[] = {"name = peter","passwd = 123",NULL}; //execle("/home/peter/2308/proc/day01_code/myproc","./myproc",NULL,env); char * arg[] = {"./myproc",NULL}; execve("/home/peter/2308/proc/day01_code/myproc",arg,env); #endif }else{ //父进程循环打印 for(i = 0 ; ; i++){ printf("我是父进程,我要努力赚钱\n"); sleep(1); } } return 0; }
3.结束进程
实例代码如下所示:
#include <stdlib.h> void exit(int status); //在结束进程之前,会先刷新缓冲,释放缓冲区,关闭打开的文件,然后再结束进程。 #include <unistd.h> void _exit(int status); //直接结束进程,不会刷新缓冲,释放缓冲区,关闭打开的文件 //参数 ---status: 0-表示正常结束,非0-表示异常结束 例如: int main(void) { printf("hello world"); //exit(1); _exit(1); while(1); return 0; //在main函数中,执行return语句,return会调用exit() }
4.给进程收尸(释放进程占用的资源)
(1)wait
#include <sys/types.h> #include <sys/wait.h> //作用:给任意一个子进程收尸 如果子进程没有结束,则父进程会阻塞,直到子进程结束为止。 如果父进程没有子进程,则wait函数立即返回。 pid_t wait(int *wstatus); //参数 ----- 保存子进程结束状态的变量地址 //返回值 ----成功:收尸的子进程的ID,失败:-1
wait实例代码如下:
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <sys/wait.h> int main(void) { int i; pid_t pid1,pid2; int status; if((pid1 = fork()) < 0){ perror("fork"); exit(1); }else if(!pid1){ for(i = 0 ; i < 7; i++){ printf("子进程1--pid = %d\n",getpid()); sleep(1); } exit(0); } if((pid2 = fork()) < 0){ perror("fork"); exit(1); }else if(!pid2){ for(i = 0 ; i < 3; i++){ printf("子进程2--pid = %d\n",getpid()); sleep(1); } exit(120); } if(wait(&status) < 0){ perror("wait"); exit(1); } printf("给子进程收完尸\n"); printf("status = %d\n",WEXITSTATUS(status)); return 0; }
(2)waitpid
//作用:给指定的进程收尸 pid_t waitpid(pid_t pid, int *wstatus, int options); //参数1 ---pid: pid > 0 给进程号为pid的子进程收尸 pid = -1 与wait()相同,给任意子进程收尸 pid = 0 给与当前进程在同一个进程组的中任意子进程收尸 pid < -1 给进程组ID为|pid|的进程组中任意子进程收尸 //参数2 ----保存子进程结束状态的变量地址 //参数3 ---- 选项,一般为0
waitpid实例代码如下:
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <sys/wait.h> int main(void) { int i; pid_t pid1,pid2; int status; if((pid1 = fork()) < 0){ perror("fork"); exit(1); }else if(!pid1){ for(i = 0 ; i < 7; i++){ printf("子进程1--pid = %d\n",getpid()); sleep(1); } exit(234); } if((pid2 = fork()) < 0){ perror("fork"); exit(1); }else if(!pid2){ for(i = 0 ; i < 3; i++){ printf("子进程2--pid = %d\n",getpid()); sleep(1); } exit(120); } if(waitpid(pid1,&status,0) < 0){ perror("wait"); exit(1); } printf("给子进程收完尸\n"); printf("status = %d\n",WEXITSTATUS(status)); return 0; }
总结
本篇文章针对进程线程进行超详细讲解,希望能够帮到大家!
以后还会给大家展现更多关于嵌入式和C语言的其他重要的基础知识,感谢大家支持懒大王!