[操作系统自由练习] 进程的创建, fork()函数
author: 泥烟
ps命令查看系统进程
ps 的参数很多, 在此仅列出几个常用的参数
-
-A 列出所有的进程
-
-w 显示加宽可以显示较多的资讯
-
-ef 显示所有命令,连带命令行
-
-au 显示较详细的资讯
-
-aux 显示所有包含其他使用者的行程
-
au(x) 输出格式 :USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
-
USER: 行程拥有者
-
%CPU: 占用的 CPU 使用率
-
%MEM: 占用的记忆体使用率
-
VSZ: 占用的虚拟记忆体大小
-
RSS: 占用的记忆体大小
-
TTY: 终端的次要装置号码 (minor device number of tty)
-
STAT: 该行程的状态
- D: 无法中断的休眠状态 (通常 IO 的进程)
- R: 正在执行中
- S: 静止状态
- T: 暂停执行
- Z: 不存在但暂时无法消除
- W: 没有足够的记忆体分页可分配
- <: 高优先序的行程
- N: 低优先序的行程
- L: 有记忆体分页分配并锁在记忆体内 (实时系统或捱A I/O)
-
-
kill -9 pid 杀死pid号的进程
kill 发送一个特定的信号 (signal) 给 pid 的进程根据该信号而做特定的动作,若没有指定,预设是送出终止 (TERM) 的信号
-
env 查看环境变量
可以发现,
所谓的父进程(37002)是由(36841, 即程序开始执行时所创建的进程)创建的
子进程(37003)占用的虚拟内存的大小是和父进程(37002)一样的
该程序中, 尽管父进程睡两秒,子进程睡一秒, 但运行时出现了连着输出了三次子进程的情况, 我觉得应该是异步性导致的
fork1.c
#include<stdio.h>
#include<unistd.h>
main()
{
int pid=fork();
if(pid == -1){
printf("fork failed.\n");
return ;
}
else if(pid > 0) printf("%d %d\n", pid, getpid());
else printf("%d %d\n", pid, getpid());
printf("child\n");
printf("father\n");
return;
}
总结
成功创建子进程,
父进程(47428)中pid这个变量(注意,不是父进程本身的pid)即fork后返回的值, 等于子进程的pid
子进程(47429)中pid这个变量为0
父子进程均输出 child father
fork2.c
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
main(int argc, char **argv)
{
int pid = fork();
if(pid == 0){
printf("Child\n");
execl("/bin/ls", "ls", 0);
perror("exce error!\n");
printf("ccc");
}
else if(pid > 0) printf("Parent\n");
else printf("FORK FAIL!\n");
printf("%d END.\n", getpid());
}
总结
成功创建子进程后,
子进程 👉 >>>“child” 👉 执行ls 👉 结束
父进程(pid=47230) 👉 >>>“Parent” 👉 >>>“END” 👉 结束
fork2plus.c (可传参)
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
main(int argc, char **argv)
{
int pid = fork();
int rtn;
if(pid == 0){
printf("Child\n");
printf("argc=%d\n", argc);
for(int i = 1; i < argc; i ++){
printf("执行%s...\n", argv[i]);
system(argv[i]);
perror(argv[i]);
}
exit(errno);
}
else if(pid > 0){
wait(&rtn);
printf("Chird is over, here is parent(%d)\n", getpid());
}
else printf("FORK FAIL!\n");
printf("%d END.\n", getpid());
}
总结
1.分析
流程与上面几个例子差不多,
利用argc argv, 实现向程序内传参
值得一提的是, 我在这里加了个wait, 等待子进程的结束
2.argc argv
百度百科
argc,argv 用命令行编译程序时有用。
主函数main中变量(int argc,char *argv[ ])的含义
有些编译器允许将 main() 的返回类型声明为void,这已不再是合法的C++
main(int argc, char *argv[ ], char **env)才是UNIX和Linux中的标准写法。
argc: 整数,用来统计你运行程序时送给main函数的命令行参数的个数
* argv[ ]: 指针数组,用来存放指向你的字符串参数的指针,每一个元素指向一个参数
argv[0] 指向程序运行的全路径名
argv[1] 指向在DOS命令行中执行程序名后的第一个字符串
argv[2] 指向执行程序名后的第二个字符串
…
argv[argc]为NULL。
**env:字符串数组。env[ ]的每一个元素都包含ENVVAR=value形式的字符
串。其中ENVVAR为环境变量,value 为ENVVAR的对应值。
argc, argv,env是在main( )函数之前被赋值的,编译器生成的可执行文件,main( )不是真正的入口点,而是一个标准的函数,这个函数名与具体的操作系统有关。
proc1.c
//进程操作
#include <unistd.h>
#include <sys/types.h>
#include <stdio.h>
#include <errno.h>
int main(int argc,char **argv)
{
pid_t pid,old_ppid,new_ppid;
pid_t child,parent;
parent = getpid(); //获得本进程PID
if((child=fork()) < 0){
fprintf(stderr, "%s:fork of child failed:%s\n", argv[0], strerror(errno));
exit(1);
}
else if(child == 0){ //子进程被调度运行
old_ppid = getppid();
sleep(2);
new_ppid = getppid();
}
else {
sleep(2);
printf("父亲(pid=%d)醒了并say good bye!\n", getpid());
exit(0); //父进程退出
}
//下面仅子进程运行
printf("Original parent:%d\n", parent);
printf("Child:%d\n", getpid());
printf("Child's old ppid:%d\n", old_ppid);
printf("Child's new ppid:%d\n", new_ppid);
exit(0);
}
总结
这里old pid 和new pid都是指子进程47489,
父进程睡完就溜了, 不会执行下面的输出操作
本文来自博客园,作者:泥烟,CSDN同名, 转载请注明原文链接:https://www.cnblogs.com/Knight02/p/16255359.html