进程创建和调度
1)进程
进程:程序的一次执行在操作系统中的影像
进程控制块(PCB):对于操作系统来说,PCB即代表整个进程
进程主要管理执行所需的资源
进程ID号:gepid/geppid
复制创建新进程:fork();
替换创建新进程:exec函数族
等待子进程的退出:wait/waitpid
进程的执行状态:新建,就绪,运行,阻塞,退出
僵尸进程:子进程退出之后,没有被父进程wait
孤儿进程:父进程在子进程之前退出,该子进程称为孤儿进程,进而被init进程收养
子进程ID: pid_t getpid
父进程ID: pid_t getppid
2)fork镜像创建新函数
fork()
#include <unistd.h>
pid_t fork(void);
2.1)字符串的分割
char *strtok(char *src, char *flag)
参数一是你要截取的字符串,参数2是字符串中的分隔符
3)exec族函数
#include <unistd.h>
后缀:-l -v (NULL结尾) -p
参数例:
extern char **environ;
int execl(const char *path, const char *arg, ...);
int execlp(const char *file, const char *arg, ...);
int execle(const char *path, const char *arg,..., char * const envp[]);
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
int execvpe(const char *file, char *const argv[],char *const envp[]);
4)父子进程
pid_t fork();
父进程创建子进程
成功返回0
失败返回-1
父子进程 1.不保证先后顺序2.不保证打断多久3.原则上保证子进程先运行
父进程先于子进程退出,子进程被init进程(1号进程)收养
5)僵尸进程
子进程结束时, 父进程会收到这个SIGCHLD信号。如果父进程没有处理这个信号,也没有等待(wait)子进程,子进程虽然终止,但是还会在内核进程表中占有表项,这时的子进程称为 僵尸进程。
5.1)查看僵尸进程
在linux中,利用命令ps,可以看到有标记为Z的进程就是僵尸进程。
ps -ef|grep defunc可以找出僵尸进程.
可以用ps的-l选项,得到更详细的进程信息. F(Flag):一系列数字的和,表示进程的当前状态。这些数字的含义为:
00:若单独显示,表示此进程已被终止。
01:进程是核心进程的一部分,常驻于系统主存。如:sched、 vhand 、bdflush 等。
02:Parent is tracing process.
04:Tracing parent’s signal has stopped the process; the parent is waiting ( ptrace(S)).
10:进程在优先级低于或等于25时,进入休眠状态,而且不能用信号唤醒,例如在等待一个inode被创建时
20:进程被装入主存(primary memory)
40:进程被锁在主存,在事务完成前不能被置换
S(state of the process )
O:进程正在处理器运行
S:休眠状态(sleeping)
R:等待运行(runable)
I:空闲状态(idle)
Z:僵尸状态(zombie)
T:跟踪状态(Traced)
B:进程正在等待更多的内存页
C:cpu利用率的估算值(cpu usage)
5.2)僵尸进程清除的方法
1.改写父进程,在子进程死后要为它收尸
2.kill -18 PPID (PPID是其父进程)这个信号是告诉父进程,该子进程已经死亡了,请收回分配给他的资源。
3.终止父进程,要先看其父进程又无其他子进程,如果有,可能需要先kill其他子进程,也就是兄弟进程,kill –15 PID1 PID2 (PID1,PID2是僵尸进程的父进程的其它子进程)。
6)wait() and waitpid()
wait族函数头文件
#include <sys/types.h>
#include <sys/wait.h>
//参数
pid_t wait(int *status);
pid_t waitpid(pid_t pid, int *status, int options);
int waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options);
//返回值
The value of pid can be:
< -1 meaning wait for any child process whose process group ID
is equal to the absolute value of pid.
-1 meaning wait for any child process.
0 meaning wait for any child process whose process group ID
is equal to that of the calling process.
> 0 meaning wait for the child whose process ID is equal to
the value of pid.
简单模拟shell脚本
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<string.h>
#include <sys/wait.h>
#define MAX_TIPS_STR_LEN 500
#define MAX_CMD_LEN 128
#define DEBUG_MODE 1
#define MAX_PATH_LEN 200
int main (int argc ,char *argv[])
{
int status = 0;
pid_t pid;
//存储命令提示符字符串
char tips_string[MAX_TIPS_STR_LEN] = {'\0'};
//存储从键盘读取的命令字符串
char command[MAX_CMD_LEN]={'\0'};
//存储当前工作目录
while(1)
{
//1.print tips 拼接命令提示符
//printf("%s",getpwuid(getuid()) -> pw_name);
//printf(">>**>>>");
//printf("%s$",getcwd(cwd,MAX_PATH_LEN));
//2.input command string form keyboard
getcwd(cwd,MAX_PATH_LEN);
sprintf(tips_string,"%S:%S$", getpwuid(getuid() ) ->pw_name, cwd);
printf("%s",tips_string);
//从键盘读取shell命令字符串,并去除'\n'
fgets(command,MAX_CMD_LEN, stdin);
//replace '\n'
command [ strlen(command) -1 ] = '\0';
//创建子进程执行读取的shell命令
//3.create a new child process to run command
if((pid = fork() ) == 0 )
{
//注意对带参数和选项的shell命令,需要对其进行划分
printf("prepare %d\n",command);
if(execlp(command, command, NULL) == -1 )
{
printf("input error\n");
return 1;
}
}
else if(pid >0)
{
//2.wait for input command
//等待子进程执行结束,并防止僵尸进程的产生
wait(NULL);
}
}
return 0;
}