进程笔记

学习笔记(二)之进程:

进程:本质是程序一次动态执行的过程 动态的 有生命周期 不能保存(临时存放于RAM上)

程序:本质是由源码编译生成的二进制可执行文件(指令和数据的集合) 静态的 无生命周期
可以报存(ROM)

注:即使是同一个程序多次执行产生进程也是不同的进程!!!

进程动态执行的一次过程:
1.创建 fork exec
2.调度
分时:将CPU的工作时间进行等均切割,进行合理分配,实现宏观上并行,微观上串行

进程基本三态: 就绪态 运行态 阻塞态

进程管理命令:
1.ps 进程信息截屏
ps -ef
ps aux

UID:用户编号
PID:进程编号 init 1 始祖进程
PPID:父进程编号
STAT:进程状态
R:运行态
T:暂停态
S:阻塞态
Z:僵尸态

<:进程优先级较高
N:进程优先级较低
s:进程的领导者
l:多线程
+:在前台运行
2.kill命令:给指定进程发送信号
kill -信号编号 PID
kill -l:列出信号 SIGINT 2 ctrl+c
SIGSTOP 19 ctrl+z
SIGKILL 9

  top 类似windows 任务管理器 q退出界面
  pstree 以树状图形式显示所有进程

3.执行 CPU执行
4.消亡 exit _exit

进程三要素:
1.程序 指令代码
2.内存分段
3.进程控制块 PCB task_struct 结构体 用于记录进程信息(PID,STAT,指向父进程的指针,记录所有子进程的列表)

getpid:获取调用进程的PID
pid_t getpid(void);

getppid:获取调用进程父进程的PID
pid_t getppid(void);

 1 #include<stdio.h>
 2 #include <sys/types.h>
 3 #include <unistd.h>
 4 
 5 
 6 
 7 int main(int argc, const char *argv[])
 8 {
 9     pid_t pid,ppid;
10     pid = getpid();
11     ppid = getppid();
12 
13     printf("%d %d\n",pid,ppid);
14     while(1)
15     {
16         ;
17     }
18 
19     return 0;
20 }
getppid

 

进程创建:fork
pid_t fork(void);
功能:将当前调用进程进行精确的拷贝产生一个新的进程,新的进程称为子进程,调用进程称为父进程
返回值:失败在父进程中返回-1,并设置errno号,子进程不会被创建
成功时,在父进程中看到的返回值是子进程的pid,在子进程中看到的返回值是0

 1 #include <stdio.h>
 2 #include <unistd.h>
 3 #include <sys/types.h>
 4 #include <stdlib.h>
 5 #include <sys/wait.h>
 6 
 7 
 8 
 9 int main(int argc, const char *argv[])
10 {
11     pid_t pid;
12     pid_t pid_ret;
13 
14 
15     pid = fork();  //该语句后子进程出现
16     if(pid < 0)   //创建子进程失败
17     {
18         perror("fail to fork");
19         exit(1);
20     }
21     else if(pid == 0) //子进程看到的代码块
22     {
23         printf("pid:%d child_pid:%d ppid:%d\n",pid,getpid(),getppid());
24         sleep(5);
25         exit(0);
26     }
27     else  // pid>0  父进程看到的代码块,得到的返回值是子进程的pid
28     {
29         printf("child_pid:%d pid:%d\n",pid,getpid());
30     //    pid_ret = wait(NULL);//阻塞等待子进程退出
31         
32     //    pid_ret = waitpid(-1,NULL,0);waitpid阻塞
33 
34     //    pid_ret = waitpid(-1,NULL,WNOHANG);waitpid非阻塞
35         printf("pid_ret:%d\n",pid_ret);
36         exit(0);
37     }
38 
39     return 0;
40 }
fork

 

进程退出:exit man 3 _exit man 2
exit
void exit(int status);
功能:退出当前进程,刷新和关闭所有打开的文件流,并返回退出状态给当前进程的父进程 status & 0377
参数:退出状态可以自定义 官方提供的宏可以直接使用 EXIT_SUCCESS 0 EXIT_FAILURE 1

_exit
void _exit(int status);
功能:立刻退出当前进程,关闭所有属于该进程的文件描述符,将所有的子进程交给init关系,给当前进程的父进程发送SIGCHLD
的信号,并返回退出状态给父进程
参数:退出状态可以自定义 官方提供的宏可以直接使用 EXIT_SUCCESS 0 EXIT_FAILURE 1

wait
pid_t wait(int *status);
功能:1.用与父进程中阻塞等待任意子进程状态改变(1.子进程退出(使用exit) 2.被信号停止 3.被信号恢复),2.当子进程退出时父进程会使用wait"收尸"(回收子进程相关资源),回收不及时会造成僵尸进程!
返回值:成功返回被回收的子进程的PID,失败返回-1
参数:如果不关子进程的状态改变,则直接填NULL
如果关心子进程状态改变,准备一个int型变量,取地址放入wait中,结合一下宏函数操作:
宏函数:
WIFEXITED(status) 判断子进程是否正常退出(使用exit _exit) 如果是返回true
WIFSIGNALED(status) 判断子进程是否被信号中断 如果是则返回true
WEXITSTATUS(status) 使用时必须保证该子进程退出时使用的时exit或者_exit退出
解析子进程使用exit函数返回status中的信息

 1 #include <stdio.h>
 2 #include <unistd.h>
 3 #include <sys/types.h>
 4 #include <stdlib.h>
 5 #include <sys/wait.h>
 6 
 7 
 8 
 9 int main(int argc, const char *argv[])
10 {
11     pid_t pid;
12 
13 
14     pid = fork();  //该语句后子进程出现
15     if(pid < 0)   //创建子进程失败
16     {
17         perror("fail to fork");
18         exit(1);
19     }
20     else if(pid == 0) //子进程看到的代码块
21     {
22         printf("pid:%d child_pid:%d ppid:%d\n",pid,getpid(),getppid());
23         sleep(10);
24         exit(2);
25     }
26     else  // pid>0  父进程看到的代码块,得到的返回值是子进程的pid
27     {
28         printf("child_pid:%d pid:%d\n",pid,getpid());
29         int s;
30         wait(&s);//阻塞等待子进程退出
31         if(WIFEXITED(s))
32         {
33             printf("child is exit!\n");
34             printf("exit_status:%d\n",WEXITSTATUS(s));
35         }
36         else if(WIFSIGNALED(s))
37         {
38             printf("child is killed by signal!\n");
39         }
40 
41         exit(0);
42     }
43 
44     return 0;
45 }
wait

 

waitpid:
pid_t waitpid(pid_t pid, int *status, int options);
参数:
1.pid:
-1:代表等待任意子进程状态发生改变
>0:(子进程pid编号)等待指定的子进程状态发生改变
0:代表等待与当前进程同一组内的所有子进程的状态发生改变
2.同wait一致
3.选项 0 默认阻塞(与wait一致) WNOHANG 默认非阻塞
返回值:成功返回回收子进程的pid号,失败返回-1,如果选项使用的是WNOHANG,则没有子进程退出时返回0
waitpid(-1,&status,0) == wait(&status)

僵尸进程:僵尸进程是问题,要解决 详见:man 2 wait NOTES
孤儿进程:不是问题,当父进程退出,子进程还没有结束,所有的子进程就变成孤儿进程,交给init管理
init能一瞬间回收所有退出的子进程
1.wait waitpid 无法同时回收多个退出的子进程,有效率问题

2.信号注册 SIGCHLD
signal
sighandler_t signal(int signum, sighandler_t handler);
功能:向内核注册指定信号,当当前进程收到该对应信号时,执行指定操作
参数:1.需要被注册的信号 2.指定操作
signal(SIGCHLD,SIG_IGN); 信号忽略操作

 1 #include <stdio.h>
 2 #include <unistd.h>
 3 #include <sys/types.h>
 4 #include <stdlib.h>
 5 #include <sys/wait.h>
 6 #include <signal.h>
 7 
 8 
 9 
10 int main(int argc, const char *argv[])
11 {
12     signal(SIGCHLD,SIG_IGN); 
13     //向内核注册SIGCHLD,当该进程收到这个信号时,选择忽略 
14 
15     pid_t pid;
16     pid_t pid_ret;
17 
18 
19     pid = fork();  //该语句后子进程出现
20     if(pid < 0)   //创建子进程失败
21     {
22         perror("fail to fork");
23         exit(1);
24     }
25     else if(pid == 0) //子进程看到的代码块
26     {
27         printf("pid:%d child_pid:%d ppid:%d\n",pid,getpid(),getppid());
28         exit(0);
29     }
30     else  // pid>0  父进程看到的代码块,得到的返回值是子进程的pid
31     {
32         sleep(3);
33         pid_ret = waitpid(-1,NULL,WNOHANG);//waitpid非阻塞
34         printf("pid_ret:%d\n",pid_ret);
35         exit(0);
36     }
37 
38     return 0;
39 }
signal

 

3.父子孙
父创建子 子立马创建孙 子自杀 父进程回收子,父做自己的事 孙交给init,孙进程做自己的事

 1 #include <stdio.h>
 2 #include <unistd.h>
 3 #include <stdlib.h>
 4 #include <sys/types.h>
 5 
 6 
 7 int main(int argc, const char *argv[])
 8 {
 9     pid_t pid1,pid2;
10 
11 
12     pid1 = fork();  //父创建子进程
13     if(pid1 < 0)
14     {
15         perror("fail to fork1");
16         exit(1);
17     }
18     else if(pid1 == 0) //子进程
19     {
20         pid2 = fork(); //子创建孙
21         if(pid2 < 0)
22         {
23             perror("fail to fork2");
24             exit(1);
25         }
26         else if(pid2 == 0)//孙进程
27         {
28             sleep(5);
29             printf("父亲被残忍杀害,爷爷不管,交给孤儿院!\n");
30             printf("getppid:%d\n",getppid());
31             exit(0);
32         }
33         else  //子进程
34         {
35             printf("惨无人道被杀害的子进程,心态爆炸!\n");
36             exit(0);
37         }
38     }
39     else  //父进程
40     {
41         wait(NULL); 
42         //回收自杀的子进程,由于子进程创建孙进程很快,不做任何事就退出,父进程等待回收时基本不会受到影响
43         printf("嘿嘿嘿!\n");
44         exit(0);
45     }
46 
47     return 0;
48 }
父子孙

 

exec函数族: 将指定的新的可执行文件替换当前进程的0~3G空间
l:list(以列表形式排布) p:path(通过shell查找) e:env 环境 v: vector
execl:
int execl(const char *path, const char *arg, ...);
参数:1.新的可执行文件的路径 2.命令行传参,以列表形式排布,以NULL结尾 3. ...代表可变长度传参

 1 #include <stdio.h>
 2 #include <unistd.h>
 3 
 4 
 5 
 6 int main(int argc, const char *argv[])
 7 {
 8     printf("before execl!\n");
 9 
10     execl("/home/xyx/teach/18072/Pro_2/hello","./hello",NULL);
11 
12     printf("after execl!\n");
13 
14     return 0;
15 }
execl

 

execlp:
int execlp(const char *file, const char *arg, ...);
参数:1.新的可执行文件名(自动查找路径) 2.命令行传参,以列表形式排布,以NULL结尾 3. ...代表可变长度传参

 1 #include <stdio.h>
 2 #include <unistd.h>
 3 
 4 
 5 
 6 int main(int argc, const char *argv[])
 7 {
 8     printf("before execlp!\n");
 9     
10     execlp("ls","ls","-l",NULL);
11 
12     printf("after execlp!\n");
13     
14     return 0;
15 }
eleclp

 

execv:
int execv(const char *path, char *const argv[]);
参数:1.新的可执行文件路径 2.命令行传承,以数组方式填写(自己准备数组,最后一个元素依旧是NULL)

 1 #include <stdio.h>
 2 #include <unistd.h>
 3 
 4 
 5 
 6 int main(int argc, const char *argv[])
 7 {
 8     printf("before execv!\n");
 9     char * a[] = {"./hello",NULL};
10     execv("/home/xyx/teach/18072/Pro_2/hello",a);
11     printf("after execv!\n");
12     return 0;
13 }
execv

 

execle:
int execle(const char *path, const char *arg, ..., char * const envp[]);
参数:1.新的可执行文件的路径 2.命令行传参,以列表形式排布,以NULL结尾 3. ...代表可变长度传参 4.自己提供的环境变量

 1 #include <stdio.h>
 2 #include <unistd.h>
 3 
 4 
 5 
 6 int main(int argc, const char *argv[])
 7 {
 8     printf("before execle!\n");
 9     char * env[] = {"PATH=hehe","LOGANNAME=heihei",NULL};
10     execle("/usr/bin/env","env",NULL,env);
11     printf("after execle!\n");
12     return 0;
13 }
execle

 

终端上执行a.out:
bash --> fork --> exec(a.out)

system:跳出进程执行shell命令,执行完成后返回当前调用进程
int system(const char *command);
参数:shell命令

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 
 4 
 5 
 6 int main(int argc, const char *argv[])
 7 {
 8     printf("before system!\n");
 9     system("ls -l");
10     printf("after system!\n");
11     return 0;
12 }
system

 

交互进程:与终端产生交互
前台进程(输入输出都存在): 后台运行过程中输入fg切换为前台运行
后台进程(只有输出): 后台运行a.out: (1) ./a.out & (2)ctrl+z暂停进程 用bg回复进程到后台运行

守护进程:与终端无关 ,从开始运行,一直到主动杀死或者操作系统结束才会终止
1.创建子进程,父进程退出,子进程交给init接管
2.设置当前进程为会话组组长
setsid:
pid_t setsid(void);
3.改变了工作路径
chdir
int chdir(const char *path);
4.更改文件权限掩码
umask(0)
mode_t umask(mode_t mask);
5.关闭文件描述符
getdtablesize: 返回当前进程能打开的最大的文件个数 1024
int getdtablesize(void);
利用for结合close循环关闭文件描述符

注:有输出时需要依靠fflush函数实现

 1 #include <stdio.h>
 2 #include <unistd.h>
 3 #include <stdlib.h>
 4 #include <sys/types.h>
 5 #include <sys/stat.h>
 6 
 7 
 8 int main(int argc, const char *argv[])
 9 {
10     pid_t  pid;
11 
12 
13     pid = fork();
14     if(pid < 0)
15     {
16 
17     }
18     else if(pid == 0)
19     {
20         //设置会话组组长
21         setsid();
22 
23         //更改工作路径
24         chdir("/home/xyx");
25 
26         //更改文件权限掩码
27         umask(0);
28 
29 
30         //关闭所有打开的文件描述符
31         int size_fd;
32         size_fd = getdtablesize();
33         int i;
34         for(i = 0;i < size_fd;i++)
35         {
36             close(i);
37         }
38         printf("11111\n");        
39         sleep(50);
40     }
41     else
42     {
43         exit(0);
44     }
45 
46 
47 
48     return 0;
49 }
守护进程
 1 #include <stdio.h>
 2 #include <unistd.h>
 3 #include <stdlib.h>
 4 #include <sys/types.h>
 5 #include <sys/stat.h>
 6 #include <time.h>
 7 
 8 
 9 int main(int argc, const char *argv[])
10 {
11     pid_t  pid;
12 
13 
14     pid = fork();
15     if(pid < 0)
16     {
17 
18     }
19     else if(pid == 0)
20     {
21         //设置会话组组长
22         setsid();
23 
24         //更改工作路径
25         chdir("/home/xyx");
26 
27         //更改文件权限掩码
28         umask(0);
29 
30 
31         //关闭所有打开的文件描述符
32         int size_fd;
33         size_fd = getdtablesize();
34         int i;
35         for(i = 0;i < size_fd;i++)
36         {
37             close(i);
38         }
39 
40         FILE *fp;
41         fp = fopen("/home/xyx/log.txt","a");
42         if(fp == NULL)
43         {
44             perror("fail to fopen");
45             exit(1);
46         }
47     
48         time_t t;
49 
50         while(1)
51         {
52             t = time(NULL);
53             fprintf(fp,"%s\n",ctime(&t));
54             fflush(fp);
55             sleep(1);
56         }
57     }
58     else
59     {
60         exit(0);
61     }
62 
63 
64 
65     return 0;
66 }
daemon_time

 

posted @ 2018-08-30 11:48  向往的生活ing  阅读(319)  评论(0编辑  收藏  举报