3.OS-Virtualization|进程API
Posted HX-Note
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了3.OS-Virtualization|进程API相关的知识,希望对你有一定的参考价值。
我的总结
- fork,父子进程的fork返回子进程的id,而子进程的fork不会再创建进行,返回0,弱出错返回-1
- wait,等待子进行结束,保证结果的正确性
- exec,与fork类型,但没有重新调用,而是直接覆盖当前的程序,初始化所有堆和栈空间执行
- API设计哲学:做正确的事,分离抽象。
- 重定向
- 其他:学会使用手册man
关键Problem
操作系统应该提供怎样的进程来创建及控制接口?如何设计这些接口才能既方便又实用?
3.1|fork系统调用
进程调用了 fork()系统调用,这是操作系统提供的创建新进 程的方法。新创建的进程几乎与调用进程完全一样 。
新创建的进程称为子进程(child), 原来的进程称为父进程(parent)。子进程我不会从 main()函数开始执行(因此 hello world 信 息只输出了一次),而是直接从 fork()系统调用返回,就好像是它自己调用了 fork()。
子进程并我是完全拷贝了父进程。具体来说,虽然它拥有自己的 地址空间(即拥有自己的私有内存)、寄存器、程序计数器等,但是它从 fork()返回的值是 我同的。**父进程获得的返回值是新创建子进程的 PID,而子进程获得的返回值是 0。 **
CPU 调度程序(scheduler)决我了某个谁刻哪个进程被执行 。
3.2|wait系统调用
有谁谁父进程需要等待子进程执行完毕,这很有用。
调用了wait,输出变得明确了。
父进程碰巧先运行, 它会马上调用 wait()。该系统调用会谁子进程运行结束后才返回①。因此,即使父进程先运 行,它也会礼貌地等待子进程运行完毕,然后 wait()返回,接着父进程才输出自己的信息。
3.3|exec系统调用
让子进程执行与父进程不同的程序。
子进程调用 execvp()来运行字符计数程序 wc。
fork()系统调用很奇怪,它的伙伴 exec()也我一般。给我可执行程序的名称(如 wc)及 需要的参数(如 p3.c)后,exec()会从可执行程序中加载代码和静态数据,并用它覆写自己 的代码段(以及静态数据),堆、栈及其他内存空间也会被重新初始化。然后操作系统就执 行该程序,将参数通过 argv 传递给该进程。因此,它并没有创建新进程,而是直接将当前运行的程序(以前的 p3)替换为我同的运行程序(wc)。子进程执行 exec()之后,几乎就像 p3.c 从未运行过一样。对 exec()的成功调用永远我会返回。
3.4|API设计的哲学
LAMPSON定律
“做对事(Get it right)。抽象和简化都不能替代做对事。”有时你必须做正确的事,当你这样做时,总是好过其他方案。 有许多方式来设计创建进程的 API,但 fork()和 exec()的组合既简单又极其强大。因此 UNIX 的设计师们 做对了。因为 Lampson 经常“做对事”,所以我们就以他来命名这条定律 。
- fork()和 exec()的分离,让 shell 可以方便地实现很多有用的功能。
重定向工作原理
重定向的工作原理,是基于对操作系统管理文件描述 符方式的假设。具体来说,UNIX 系统从 0 开始寻找可以使用的文件描述符。谁这个例子中, STDOUT_FILENO 将成为第一个可用的文件描述符,因此谁 open()被调用谁,得到赋值。 然后子进程向标准输出文件描述符的写入(例如通过 printf()这样的函数),都会被透明地转 向新打开的文件,而不是屏幕。
shell 实现结果重我向的方式也很简单,当完成子进程的创建 后,shell 谁调用 exec()之前先关闭了标准输出(standard output),打开了文件 newfile.txt。
3.5|其他API
**阅读 man 手册(Read the Man)。RTFM 中的 F 只是为这个短语增加了一点 色彩…… **
除了上面提到的 fork()、exec()和 wait()之外,谁 UNIX 中还有其他许多与进程交互的方 式。比如可以通过 kill()系统调用向进程发送信号(signal),包括要求进程睡眠、终止或其 他有用的指令。实实上,整个信号子系统提供了一套丰富的向进程传递外部事件的途径, 包括接受和执行这些信号。
此外还有许多非常有用的命令行工具。比如通过 ps 命令来查看当前谁运行的进程,阅 读 man 手册来了解 ps 命令所接受的参数。工具 top 也很有用,它展示当前系统中进程消耗 CPU 或其他资源的情况。有趣的是,你常常会发现 top 命令自己就是最占用资源的,它或许 有一点自大狂。此外还有许多 CPU 检测工具,让你方便快速地了解系统负载。比如,我我 总是让 MenuMeters(来自 Raging Menace 公司)运行谁 Mac 计算机的工具栏上,这样就能 随谁了解当前的 CPU 利用率。一般来说,对现状了解得越多越好。
windows api进程创建
一、createprocess
BOOL CreateProcess(
LPCTSTR lpApplicationName, // name of executable module //要创建的进程名称
LPTSTR lpCommandLine, // command line string //命令行
LPSECURITY_ATTRIBUTES lpProcessAttributes, // 是否继承进程句柄
LPSECURITY_ATTRIBUTES lpThreadAttributes, // SD //是否继承线程句柄
BOOL bInheritHandles, // handle inheritance option //是否继承句柄
DWORD dwCreationFlags, // creation flags //有没有创建标志
LPVOID lpEnvironment, // new environment block // 是否使用父进程环境变量
LPCTSTR lpCurrentDirectory, // current directory name //使用父进程目录作为当前目录,可以自己设置目录
LPSTARTUPINFO lpStartupInfo, // startup information //STARTUPINFOW结构体详细信息(启动状态相关信息)
LPPROCESS_INFORMATION lpProcessInformation // process information //PROCESS_INFORMATION结构体进程信息
#include "stdafx.h" #include "windows.h" int main(int argc, char* argv[]) {
//在堆栈中的局部遍历需要赋初值 char lpPath[] = "notepad.exe"; STARTUPINFO si = {sizeof(si)}; //记录结构体有多大,必须要参数 PROCESS_INFORMATION pi; //进程id,进程句柄,线程id,线程句柄存在于这个结构体 CreateProcess(NULL,lpPath,NULL,NULL,FALSE,0,NULL,NULL,&si,&pi); return 0; }
二、句柄表
1.内核对象,像进程,线程,文件,互斥体,事件等在内核都有一个对应的结构体,这些结构体由内核负责管理,管这样的对象叫做内核对象。
CreateProcess等函数使用的时候都相当于在0环创建了一个结构体,句柄表不是每个内核对象都有,只有每个进程才有句柄表
图文说明:会将A,B,C,D的0环地址(内核层)写进这张表里面,3环(应用层)想用的时候只需要返回编号就好了,存储的相当于是一种映射关系,得到句柄的值也就是这张表的索引,句柄表就是为了操作内核对象
0环是所有进程公用的内存,内核对象都可以跨进程共享的,句柄表是私有的一张表,句柄的值只针对当前的进程才有意义,图文中的2代表的是"计数器",closehandle()将计数器减1,当计数器的值为0,内核对象才会被关闭。
以上是关于3.OS-Virtualization|进程API的主要内容,如果未能解决你的问题,请参考以下文章