4.2.1 进程控制的概念

进程控制的概念

  • 在进程生存全期间,对其全部行为的控制
  • 存在四个典型的控制行为
    • 创建进程
    • 阻塞进程
    • 撤销进程
    • 唤醒进程

进程创建

功能:创建一个具有制定标识(ID)的进程

参数:进程标识、优先级、进程起始地址、CPU初始状态、资源清单等。

创建进程的过程

  • 创建一个空白PCB
  • 获得并赋予进程标识符ID
  • 为进程分配空间
  • 初始化PCB
    • 默认值
  • 插入相应的进程队列
    • 新进程插入就绪队列

进程创建的伪代码

// CPU的状态,内存,优先级
Create(Si, Mi, Pi) {
// 分配新的PCB
p = Get_New_PCB();
// 分配进程的PID
pid = Get_New_PID();
// 设置进程的PID
p->ID = pid;
// CPU的状态
p->CPU_State = Si;
// 内存
p->Memory = Mi;
// 优先级
p->Priority = Pi;
// 进程状态
p->Status.Type = "Ready";
// 进程队列RL:Ready List
p->Status.List = RL;
...;
// 将进程p插入到就绪队列
Insert(RL, p);
// 调度程序
Scheduler();
}

进程撤销

功能

  • 撤销一个指定的进程
  • 收回进程所占有的资源,撤销该进程的PCB

进程撤销的时机/事件

  • 正常结束
  • 异常结束
  • 外界干预

进程撤销的实现

  • 在PCB队列中检索出该PCB
  • 获取该进程的状态
  • 若该进程处在运行态,立即终止该进程
    • 【递归】检查是否有子进程,先撤销子进程
  • 释放进程占有的资源
  • 将进程从PCB队列移除

进程阻塞

功能:停止进程的执行,变为阻塞

阻塞的时机/事件

  • 请求系统服务

    • 由于某种原因,OS不能立即满足进程的要求
  • 启动某种操作
    • 进程启动某操作,阻塞等待该操作完成
  • 新数据尚未到达
    • A进程要获得B进程的中间结果,A进程等待
  • 无新工作可做
    • 进程完成任务后,自我阻塞,等待新任务到达

参数

  • 阻塞原因
  • 不同原因构建有不同的阻塞队列

进程阻塞的实现

  • 停止运行
  • 将PCB“运行态“改”阻塞态“
  • 插入相应原因的阻塞队列
  • 转调度程序

进程唤醒

功能:唤醒处于阻塞队列的某一个进程

引起唤醒的时机/事件

  • 系统服务由不满足到满足
  • I/O完成
  • 新数据到达
  • 进程提出新请求(服务)

参数:被唤醒进程的标识

原语

原语是由若干指令构成具有特定功能的函数

具有原子性,其操作不可分割

进程创建的原语:(同上伪代码),所以进程创建是一个原语

进程控制原语

  • 创建原语
  • 撤销原语
  • 阻塞原语
  • 唤醒原语

4.2.2 Windows进程控制

Windows启动EXE程序创建进程的方法

思考:Windows如何通过编程启动exe程序创建进程?

#include <iostream>
#include <Windows.h>
using namespace std; const char* NOTEPAD_PATH = "C:/Windows/System32/notepad.exe"; int main() {
system(NOTEPAD_PATH);
WinExec(NOTEPAD_PATH, SW_SHOWNORMAL);
ShellExecute(NULL, (LPCWSTR)L"open", (LPCWSTR)L"notepad.exe", NULL, NULL, SW_SHOWMAXIMIZED); PROCESS_INFORMATION pi;
STARTUPINFO si;
BOOL ret = CreateProcess(NULL, (LPWSTR)L"notepad.exe", NULL, NULL, FALSE, NULL, NULL, NULL, &si, &pi); return 0;
}

以下三个函数都是对CreateProcess的封装

_DCRTIMP int __cdecl system(
_In_opt_z_ char const* _Command
); WinExec(
_In_ LPCSTR lpCmdLine,
_In_ UINT uCmdShow
); SHSTDAPI_(HINSTANCE) ShellExecuteW(_In_opt_ HWND hwnd, _In_opt_ LPCWSTR lpOperation, _In_ LPCWSTR lpFile, _In_opt_ LPCWSTR lpParameters,
_In_opt_ LPCWSTR lpDirectory, _In_ INT nShowCmd);

CreateProcess()创建进程

CreateProcessW(
_In_opt_ LPCWSTR lpApplicationName, // 可执行程序名
_Inout_opt_ LPWSTR lpCommandLine, // [可执行程序名]程序参数
_In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes,
_In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes,
_In_ BOOL bInheritHandles,
_In_ DWORD dwCreationFlags, // 创建标志(优先级……)
_In_opt_ LPVOID lpEnvironment,
_In_opt_ LPCWSTR lpCurrentDirectory,
_In_ LPSTARTUPINFOW lpStartupInfo, // 启动信息(进程启动的状态,是否显示窗口……)
_Out_ LPPROCESS_INFORMATION lpProcessInformation //
);

创建新进程

  • 创建进程内核对象,创建虚拟地址空间
  • 装载EXE和/或DLL的代码和数据到地址空间中
  • 创建主线程和线程内核对象
  • 启动主线程,进入主函数(main)
STARTUPINFO si = { sizeof(si) };
PROCESS_INFORMATION pi;
::CreateProcess((LPWSTR)L"C:/Windows/System32/notepad.exe", (LPWSTR)L"C:/readme.txt", NULL, NULL, FALSE, NULL, NULL, NULL, &si, &pi);

结束进程

  • ExitProcess
WINBASEAPI DECLSPEC _NORETURN VOID WINAPI ExitProcess(UINT uExitCode);
  • TerminateProcess
WINBASEAPI WINBOOL WINAPI TerminateProcess(HANDLE hProcess, UINT uExitCode);

4.2.3 Linux进程控制

创建进程

pid_t fork(void);

例子:

pid_t pid = fork();
#include <unistd.h>
#include <cstdio> int main() {
pid_t pid;
int count = 0;
pid = fork();
printf("This is first time, pid = %d\n", pid);
printf("This is second time, pid = %d\n", pid);
count++;
printf("count = %d\n", count);
if (pid > 0) {
printf("This is the parent process,the child has the pid:%d\n", pid);
} else if (!pid) {
printf("This is the child Process.\n");
} else {
printf("fork failed.\n");
}
printf("This is third time, pid = %d\n", pid);
printf("This is fouth time, pid = %d\n", pid);
return 0;
}

运行结果

This is first time, pid = 1174
This is second time, pid = 1174
count = 1
This is the parent process,the child has the pid:1174
This is third time, pid = 1174
This is fouth time, pid = 1174
This is first time, pid = 0
This is second time, pid = 0
count = 1
This is the child Process.
This is third time, pid = 0
This is fouth time, pid = 0 Process finished with exit code 0
  • 新进程是当前进程的子进程
  • 父进程和子进程
    • 父进程:fork()的调用者
    • 子进程:新建的进程
  • 子进程是父进程的复制
    • 子进程和父进程有相同代码、数据、堆栈
    • 子进程的行为和父进程的行为一模一样
    • 子进程和父进程唯一不同的是PID
  • 子进程和父进程可以并发运行

思考:下面程序在屏幕上将输出什么内容

int main() {
fork(); // 子进程是父进程的复制,父子进程都输出了
printf("Hello World!\n"); return 0;
}

输出结果:

父子进程在并发运行

思考:下面程序运行结果是什么

#include <unistd.h>
#include <cstdio> int main() {
pid_t pid;
pid = fork();
if (pid == 0) {
printf("Hello World!\n");
} else if (pid > 0) {
printf("How are you!\n");
} return 0;
}

输出结果:

父子进程谁先输出不确定

fork返回值pid**

Upon successful completion, fork() returns a value of 0 to the child process and returns the process ID of the child process to the parent process. Otherwise, a value of -1 is returned to the parent process, no child process is created, and the global variable errno is set to indicate the error.

  • 在子进程中,pid=0
  • 在父进程中,pid>0(子进程ID)
  • 出错:pid=-1

修改:增加输出pid,运行结果如下

PID of current Process is : 1609
How are you! // 父进程
PID of current Process is : 0
Hello World! // 子进程 Process finished with exit code 0

fork函数的实现

在文件/kernel/fork.c中

int do_fork(unsigned long clone_flags,
unsigned long stack_start,
unsigned long stack_size,
int __user *parent_tidptr,
int __user *child_tidptr) {
struct task_struct *p;
// 分配无力页面存放task_struct结构和内核空间的堆栈
p = alloc_task_struct();
// 把当前进程的task_struct结构中所有内容拷贝到新进程中
*p = *current;
// 判断用户进程数量是否超过了最大限制,否则不许fork
if ((&p->user->processes) >= p->rlim[RLIMIT_NPROC].rlim_cur) {
goto bad_fork_free;
}
// 子进程状态设TASK_UNINTERRUPTIBLE
p->state = TASK_UNINTERRUPTIBLE;
// 拷贝进程的所有信息
copy_files(clone_flags, p);
copy_fs(clone_flags, p);
copy_mm(clone_flags, p);
// 进程创建后与父进程链接起来形成一个进程组
list_add(&p->thread_group, &current->thread_group);
// 唤醒进程,将其挂入可执行队列等待被调度
wake_up_process(p);s
}
  • 为子进程分配task_struct空间
  • 初始化子进程task_struct
  • 复制父进程的file,fs,sighand,mm等信息
  • ……

进程执行与父进程不同的功能

exec函数簇(包括若干函数)

  • 功能

    • 装入一个指定的可执行程序运行
    • 使子进程具有和父进程完全不同的新功能
  • 步骤

    1. 根据文件名找到相应的可执行程序
    2. 将可执行程序的内容填入子进程的地址空间
    3. 进入新进程执行且不再返回
// unistd.h
int execl(const char * __path, const char * __arg0, ...) __WATCHOS_PROHIBITED __TVOS_PROHIBITED;
int execle(const char * __path, const char * __arg0, ...) __WATCHOS_PROHIBITED __TVOS_PROHIBITED;
int execlp(const char * __file, const char * __arg0, ...) __WATCHOS_PROHIBITED __TVOS_PROHIBITED;
int execv(const char * __path, char * const * __argv) __WATCHOS_PROHIBITED __TVOS_PROHIBITED;
int execve(const char * __file, char * const * __argv, char * const * __envp) __WATCHOS_PROHIBITED __TVOS_PROHIBITED;
int execvp(const char * __file, char * const * __argv) __WATCHOS_PROHIBITED __TVOS_PROHIBITED;

【av68676164(p18-p20)】进程控制的更多相关文章

  1. 【linux草鞋应用编程系列】_2_ 环境变量和进程控制

    一. 环境变量     应用程序在执行的时候,可能需要获取系统的环境变量,从而执行一些相应的操作.     在linux中有两种方法获取环境变量,分述如下.   1.通过main函数的参数获取环境变量 ...

  2. 【Linux程序设计】之进程控制&守护进程

    这个系列的博客贴的都是我大二的时候学习Linux系统高级编程时的一些实验程序,都挺简单的. 实验题目:Linux环境下的进程控制 实验目的:熟悉并掌握Linux环境下进程的相关函数的应用:守护进程的概 ...

  3. linux进程及进程控制

    Linux进程控制   程序是一组可执行的静态指令集,而进程(process)是一个执行中的程序实例.利用分时技术,在Linux操作系统上同时可以运行多个进程.分时技术的基本原理是把CPU的运行时间划 ...

  4. (六) 一起学 Unix 环境高级编程 (APUE) 之 进程控制

    . . . . . 目录 (一) 一起学 Unix 环境高级编程 (APUE) 之 标准IO (二) 一起学 Unix 环境高级编程 (APUE) 之 文件 IO (三) 一起学 Unix 环境高级编 ...

  5. UNIX环境高级编程笔记之进程控制

    本章重点介绍了进程控制的几个函数:fork.exec族._exit.wait和waitpid等,主要需要掌握的是父进程和子进程之间的运行机制,怎么处理进程的正常和异常终止.以及怎么让进程执行不同的程序 ...

  6. Linux进程控制(二)

    1. 进程的创建 Linux下有四类创建子进程的函数:system(),fork(),exec*(),popen() 1.1. system函数 原型: #include <stdlib.h&g ...

  7. 进程控制之exec函数

    用fork函数创建子进程后,子进程往往要调用一种exec函数以执行另一个程序.当进程调用一种exec函数时,该进程执行的程序完全替换为新程序,而新程序则从其main函数开始执行.因为调用exec并不创 ...

  8. Linux C 程序 进程控制(17)

    进程控制 1.进程概述现代操作系统的特点在于程序的并行执行.Linux是一个多用户多任务的操作系统.ps .pstree 查看进程进程除了进程id外还有一些其他标识信息,可以通过相应的函数获得.// ...

  9. linux 命令及进程控制

    main.c  main.o/main.obj  main/main.exe          编译                连接 程序运行;      两步: gcc/g++  -c  mai ...

随机推荐

  1. 数据可视化之分析篇(八)Power BI数据分析应用:结构百分比分析法

    https://zhuanlan.zhihu.com/p/113113765 PowerBI数据分析02:结构百分比分析法 作者:海艳 结构百分比分析法,又称纵向分析,是指同一期间财务报表中不同项目间 ...

  2. T4 分配时间 题解

    问题描述 小王参加的考试是几门科目的试卷放在一起考,一共给 t 分钟来做.他现在已经知道每 门科目花的时间和得到的分数的关系,还有写名字要的时间(他写自己的名字很慢)请帮他 算一下他最高能得几分.总分 ...

  3. 【软件安装】在 CentOS 7(Linux)上部署流媒体服务(Tengine、ffmpeg、Centos 7、nginx-http-flv-module、OBS)

    Centos7+Tengine+Nginx-http-flv-module+ffmpeg+OBS搭建流媒体服务器 一.需求和背景 视频直播是基于领先的内容接入.分发网络和大规模分布式实时转码技术打造的 ...

  4. Windows搭建Redis集群-详细教程

    一.集群知识 1.集群的概念 所谓的集群,就是通过添加服务器的数量,提供相同的服务,从而让服务器达到一个稳定.高效的状态. 2.使用redis集群的必要性 问题:我们已经部署好了redis,并且能启动 ...

  5. 02 安装net-tools工具

    01 登录虚拟机,没错,还是那个熟悉的黑窗口 02 输入用户名密码(我还是习惯使用root用户,因为,它可以为所欲为) 小知识:注意红色框内的符号: 一般用户为限制用户,符号为:$ 超级用户,为无限制 ...

  6. ant design pro/前端/JS:实现本地运行https

    工具:github---mkcert 用于生成本地证书 ant p版本:1.0.0 这里我只说如何给antp部署https,以及会遇到的问题解决,其他请看原文参考 1.用mkcert生成证书,去git ...

  7. 题解 CF13E 【Holes】

    这个题和$P3203\ $弹飞绵羊基本上完全一致 我的做法是用\(LCT\)维护信息,开一个节点\(fly\),表示到此节点时,小球会弹飞,那么查询弹多少次即为\(siz[fly]-1\) 最后一次落 ...

  8. 水题-------判断Digit Generator

    题目链接:https://vjudge.net/problem/UVA-1583 题意:给出一个数N,判断最小的数x使x+(x各位数字的和)=N 题解:这是一个暴力求解题,不过有技巧,x各位数字的和最 ...

  9. Spring Boot+Socket实现与html页面的长连接,客户端给服务器端发消息,服务器给客户端轮询发送消息,附案例源码

    功能介绍 客户端给所有在线用户发送消息 客户端给指定在线用户发送消息 服务器给客户端发送消息(轮询方式) 项目搭建 项目结构图 pom.xml <?xml version="1.0&q ...

  10. 浅谈CSRF(Cross-site request forgery)跨站请求伪造

    本文目录 CSRF是什么 CSRF攻击原理 CSRF攻击防范 CSRF是什么 CSRF(Cross-site request forgery)跨站请求伪造,也被称为“One Click Attack” ...