当前位置:网站首页>多进程编程(一):基本概念
多进程编程(一):基本概念
2022-07-02 23:05:00 【HDD615】
1、基本概念
- 进程: 一个正在执行的应用程序,是操作系统 资源分配 的基本单元
- 线程: 是正在执行的应用程序里面的一个具体任务,是操作系统 资源调度 的基本单元
- 进程和线程间的关系:
进程可以包括很多个线程,为线程提供必备的资源,所有的线程共享这些资源。每个线程负责完成一个具体的任务,线程间相互配合,共同保证进程正常运行。同时,线程也有自己的私有资源。
2、进程的状态
- 就绪态、运行态、阻塞态

运行态: 进程占有处理器正在运行
就绪态: 进程具备运行的条件,正在等待系统分配处理器,然后开始运行
阻塞态: 进程不能够直接运行,正在等待某个事件结束,然后进入就绪态
Linux环境下,查看筛选进程的shell命令
ps -ef:查看系统的全部进程ps aux:查看系统的全部进程ps -ef | grep demo:从全部进程中,筛选出和demo相关的进程- 杀死进程:
kill -9 pid_t
3、创建进程
fork()
- 必备头文件
#include <sys/types.h> #include <unistd.h> - 用于产生一个子进程,函数返回值
pid_t是一个整数,在父进程中,返回值是子进程编号;在子进程中,返回值是0。如果创建失败,则返回 -1。pid_t fork(void); - 特点:
1、fork()函数所创建的子进程是父进程的完整副本,复制了父进程的资源
写时复制:刚创建子进程后,父子进程对于变量是共享的,只要在任一进程对数据执行了写操作时,复制才会发生(数据就不共享了,先是缺页中断,然后操作系统给子进程分配内存,并复制父进程的数据)。
2、子进程拥有自己的虚拟地址空间,父子进程数据独有,代码共享(fork()函数后的代码)
3、根据返回值,来判断是父进程还是子进程 - 举例:
打印输出#include <stdio.h> #include <sys/types.h> #include <unistd.h> int main() { pid_t res; res = fork(); if (res > 0) { printf("This is parent, pid = %d\n", getpid()); } else if (res == 0) { printf("This is child, pid = %d\n", getpid()); } else { perror("fork"); } return 0; }This is parent, pid = 3543 This is child, pid = 3544
vfork()
必备头文件
#include <sys/types.h> #include <unistd.h> pid_t vfork(void);特点:
1、返回值和fork()函数相同。
2、vfork()不创建子进程的虚拟地址,直接共享父进程的,从而物理地址也被共享了
3、子进程先运行,在子进程调用exec(进程替换)或者exit之后,父进程被调度执行举例:
#include <stdio.h> #include <sys/types.h> #include <unistd.h> #include <stdlib.h> int main() { int num = 10; pid_t res; res = vfork(); if (res > 0) { printf("This is parent, pid = %d\n", getpid()); num += 10; printf("num = %d\n", num); } else if (res == 0) { printf("This is child, pid = %d\n", getpid()); num += 10; printf("num = %d\n", num); exit(0); } else { perror("vfork"); } return 0; }打印输出
This is child, pid = 4495 num = 20 This is parent, pid = 4494 num = 30从输出结果可以看出,子进程先执行,在子进程调用
exit(0)退出之后,父进程再执行。
并且,父子进程共享num变量。
fork()和vfork()的不同之处:
fork()复制父进程的页表项,当进行写操作时,内核给子进程分配一个新的内存页面vfork()与父进程共享页表项,当写操作时,直接写在父进程的内存页面fork()创建的子进程与父进程之间的执行次序不确定vfork()是子进程先运行,在子进程调用exec(进程替换)或者exit之后,父进程被调度执行vfork()保证子进程先运行,在子进程调用exec或exit之后父进程才可能被调度运行。如果在
调用这两个函数之前子进程依赖于父进程的进一步动作,则会导致死锁。
4、exec函数族
有时候,我们需要在子进程中执行其它程序,即替换当前进程映像,这时候会使用exec函数族中的一些函数。
**作用:**根据指定的文件名找到可执行文件,并用它来取代调用进程的内容(在调用进程内部执行一个可执行文件)
返回值:exec函数族的函数执行成功后不会返回,只有调用失败了,才会返回-1,回到源程序的调用点接着往下执行。
常用函数:
1、
int execl(const char *pathname, const char *arg, ...); - pathname: 要执行的可执行文件的路径 - arg: 执行可执行文件所需要的参数列表 arg一般填写当前执行程序的名字,后面依次是可执行程序所需要的参数列表,参数最后要以 NULL 结束。 - 返回值: 当调用失败时,才有返回值,返回-1。2、
int execlp(const char *file, const char *args, ...); - 和 execl 基本一致,不过对于file会从环境变量中寻找。
5、孤儿进程
定义: 父进程结束运行,但是子进程还在运行,这样的子进程为孤儿进程(父死子在)。
注意: 每当出现一个孤儿进程的时候,内核就把孤儿进程的父进程设置为 init,而 init进程会循环地 wait() 它的已经退出的子进程。这样当一个孤儿进程结束生命周期的时候,init()进程就会处理它的一切善后工作。
因此,孤儿进程并不会有什么危害。
6、僵尸进程
当子进程结束运行时,内核不会立即释放该进程的进程表表项,以满足父进程后续对该子进程退出信息的查询(如果父进程还在运行)。
在子进程结束运行后,父进程回收子进程状态前,该子进程为僵尸进程。内核资源有限,不允许产生大量的僵尸进程。
僵尸进程不能被 kill -9 杀死。
可以在父进程中使用 wait() 或者 waitpid() 函数,以等待子进程的结束,并获取子进程的返回信息,从而避免了僵尸进程的产生,或者使子进程的僵尸态立即结束。
#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *wstatus);
- 功能:等待任意一个子进程结束,并回收子进程。
- 参数:wstatus, 进程退出时的状态信息,传入的是一个int类型的指针(传出参数)
- 返回值:
成功:返回被回收的子进程的id
失败:-1(所有子进程都结束,调用函数失败)
注意: 调用 wait() 函数的进程会被挂起(阻塞),直到它的一个子进程退出或者收到一个不能被忽略的信号时才被唤醒。
如果没有子进程了,函数立刻返回-1;
如果子进程都已经结束了,也会立即返回,返回 -1。
边栏推荐
- Use of cocospods
- Chapter 4 of getting started with MySQL: data types stored in data tables
- 经济学外文文献在哪查?
- 大学生课堂作业2000~3000字的小论文,标准格式是什么?
- Hit the industry directly! The propeller launched the industry's first model selection tool
- [shutter] shutter photo wall (center component | wrap component | clickrrect component | stack component | positioned component | button combination component)
- Open Source | Wenxin Big Model Ernie Tiny Lightweight Technology, Accurate and Fast, full Open Effect
- 130 pages of PPT from the brick boss introduces the new features of Apache spark 3.2 & 3.3 in depth
- 接口自动化覆盖率统计——Jacoco使用
- Which websites can I search for references when writing a thesis?
猜你喜欢

Talk with the interviewer about the pit of MySQL sorting (including: duplicate data problem in order by limit page)

容器运行时分析

Understanding and application of least square method

接口差异测试——Diffy工具

基于OpenCV实现口罩识别

95 pages of smart education solutions 2022

TypeError: Cannot read properties of undefined (reading ***)

Practical series - free commercial video material library

Additional: token; (don't read until you finish writing...)

35 pages dangerous chemicals safety management platform solution 2022 Edition
随机推荐
How much do you know about synchronized?
How QT exports data to PDF files (qpdfwriter User Guide)
130 pages of PPT from the brick boss introduces the new features of Apache spark 3.2 & 3.3 in depth
有哪些比较推荐的论文翻译软件?
The privatization deployment of SaaS services is the most efficient | cloud efficiency engineer points north
What is the standard format of a 2000-3000 word essay for college students' classroom homework?
Shell脚本基本使用
Bloom filter
Markdown使用教程
Maya fishing house modeling
sysdig分析容器系统调用
Top Devops tool chain inventory
Feature Engineering: summary of common feature transformation methods
Luogu_ P1149 [noip2008 improvement group] matchstick equation_ Enumeration and tabulation
[shutter] open the third-party shutter project
Implement the foreach method of array
leetcode 650. 2 Keys Keyboard 只有两个键的键盘(中等)
JS interviewer wants to know how much you understand call, apply, bind no regrets series
Luogu_ P2010 [noip2016 popularization group] reply date_ Half enumeration
附加:token;(没写完,别看…)