C语言简单进程
2015-09-12 22:08
459 查看
进程:
进程是正在运行的程序的实例
进程是一个具有独立功能的程序关于某个数据集合的一次运行活动
是系统进行(资源分配和调度)的基本单位,是操作系统结构的基础
是一个动态的概念,是一个活动的实体
init是个有超级权限的用户进程
执行态(Running):包括运行和就绪
睡眠(sleeping):
(S)浅睡眠 interruptable 进程在等待一个事件的发生或者某种系统资源,可响应异步信号
(D)深睡眠 uninterruptable 无法响应异步信号, kill -9 是杀不死的,
停止态(sTopped)进程被暂停或者跟踪状态(pause/trace) ctrl+Z
僵尸态(Zombie) 进程处于退出状态,不能被调度,但是PCB还没有被释放.
如子进程退出,父进程没有回收资源而且还在继续运行,这样就会造成子进程变成僵尸进程
实例一:进程创建
2个进程执行输出。然后开另外一个终端,kill掉父进程,
子进程会继续执行,但父进程会变为1,不是此程序的父进程了。
在console中按ctrl+c,那是会给当前所有的会话中的进程发信号。
所以要用kill,但kill掉父进程后,再用ctrl+c也kill不掉子进程的。
也要用kill。但如果先kill掉子进程,再ctrl+c就可以kill掉父进程。
实例二:
实例三:
相关函数介绍:
fork: 用fork创建子进程,
返回值为-1的时候表示没有创建成功
创建成功的话,0是给子进程; 子进程ID返回给父进程
父、子进程共享正文段,不共享数据空间、堆、栈;
子进程也是由父进程调用FORK后的代码开始执行,变量有独立的拷贝
IO缓冲区也有拷贝
写时复制COW ( COPY ON WRITE)
fork创建后,不保证两进程的调用顺序,
也就是根据系统当前环境不同,可能先调用父进程也可能先调用子进程
vfork: 可以保证子进程先调, 直到子进程调用的exit或者是exec后,父进程才运行
vfork产生的子进程是和父进程共用资源,数据和代码都共享
exec 函数族:(令子进程“脱胎换骨”)
调用的exec后,如果启动成功,子进程就被新执行程序替换了,只保留了进程号, 其它都被替换;
启动失败就返回-1
man 3 environ
execl: exec list 用list挨个写cmd
execv: exec v 指针数组写cmd
execlp: execl path 使用系统环境变量PATH对应的路径中去寻找对应的可执行文件
execvp: exec vp
execle: execl env 环境变量,也是用指针数值去写env
execve: exec ve ---- 内核调用
进程的退出:
_exit(0); 必须是自带有刷写io缓存的动作才能显示出来,这个退出函数是不会关闭IO缓冲区的
exit(); 是会处理退出处理函数的,而且会关闭IO缓冲区
孤儿进程:父进程先于子进程结束了,
这个时候子进程就变成孤儿进程,会由init进程接管;
该孤儿进程结束时候,init会自行回收资源
在bash里面调用一个可执行文件./func , func执行完了就会有一个信号SIGCHLD返回给bash
bash 收到信号后,就会显示gec@ubuntu:/mnt/hgfs/94/系统编程/0910/code$
即使现在还有孙子进程,bash也是不管,但是如果孙子进程要打印数据,依旧是在bash窗口里面显示
atexit 注册进程正常退出时候的处理程序, 注册的顺序和处理的顺序是相反的
atexit(func1) in atexit.c
进程同步(回收资源)
在进程结束的时候回收对应资源
如:之前在虚拟内存里面的申请到的堆数据,
如果进程是一直运行并且不断申请内存而不释放, 就会导致内存泄漏;
如果一个子进程结束时候没有被父进程回收资源,在父进程存在期间,它是作为僵尸进程;
只有父进程结束时候,它由1号进程init收养后,init会回收该僵尸进程资源
wait ():
等待子进程结束并回收资源
等待任意一个子进程
waitpid():
有所扩展的wait
#include <sys/wait.h>
pid_t wait(int *stat_loc);
pid_t waitpid(pid_t pid, int *stat_loc, int options);
int status ;
pid_t id;
id = wait(&status); < == > id = waitpid(-1, &status,0);
在waitpid里面的
pid > 0 就是等待具体的一个进程,其进程号为PID
= 0 等待本进程组里任意子进程
= -1 等待任意一个子进程
< -1 , 等待ID为pid绝对值的进程组里的任意一个子进程
option
WNOHANG, 不需要有已结束进程,立刻返回,不会挂起,也就是不等待
WUNTRACED 若进程被暂停,sTop了,立即返回
WCONTINUED :子进程收到SIGCONT立刻返回
进程的终止:
5种正常
从main返回;
return 0;
调用exit函数;
会先执行一些清理处理,包括调用执行处理终止程序,关闭所有标准I/O流等,然后返回内核
调用_exit或_Exit函数;立即进入内核。
最后一个线程从其启动例程返回;
从最后一个线程调用pthread_exit;
3种异常
调用abort; SIGABRT
接到一个信号并终止;ctrl+c ctrl +\
最后一个线程对取消请求作出响应;
实例二:
进程是正在运行的程序的实例
进程是一个具有独立功能的程序关于某个数据集合的一次运行活动
是系统进行(资源分配和调度)的基本单位,是操作系统结构的基础
是一个动态的概念,是一个活动的实体
init是个有超级权限的用户进程
执行态(Running):包括运行和就绪
睡眠(sleeping):
(S)浅睡眠 interruptable 进程在等待一个事件的发生或者某种系统资源,可响应异步信号
(D)深睡眠 uninterruptable 无法响应异步信号, kill -9 是杀不死的,
停止态(sTopped)进程被暂停或者跟踪状态(pause/trace) ctrl+Z
僵尸态(Zombie) 进程处于退出状态,不能被调度,但是PCB还没有被释放.
如子进程退出,父进程没有回收资源而且还在继续运行,这样就会造成子进程变成僵尸进程
实例一:进程创建
#include <stdio.h> #include <unistd.h> #include <stdlib.h> int global = 10; int main(void) { //printf("pid = %d , ppid = %d \n", (int)getpid(), (int)getppid() ); //while(1); pid_t id;//注意创建子进程返回的类型 int val = 100; printf("before fork \n"); id = fork();//创建子进程 if(id < 0 ) { printf("Fork failed \n"); // perror exit(1); } else if(id == 0) { val--; global--; printf("in Child process %d, %d\n", val,global); printf("pid = %d , ppid = %d \n ", getpid(), getppid() ); } else if(id > 0) { //sleep(1); /* 1、fork创建后,不保证两进程的调用顺序, 也就是根据系统当前环境不同,可能先调用父进程也可能先调用子进程 2、在这不加sleep,先执行父进程,然后父进程结束之后就执行父进程的父进程即是bash 也就会先输出root@xx:,然后再输出子进程的内容, 这时的子进程的父进程就不是此程序了,是被遗弃给了init。 3、加上sleep就是先让子进程先显示,然后再显示出父进程的。 子进程的父进程就也是此程序了,可以看pid。 4、父、子进程共享正文段,不共享数据空间、堆、栈; 子进程也是由父进程调用FORK后的代码开始执行,变量有独立的拷贝 所以2个进程的val和global都不互相影响 */ val --; global--; printf("in Parent process %d, %d\n", val,global); printf("pid = %d , ppid = %d \n ", (int)getpid(), (int)getppid() ); } // return 0; exit(0); // _exit(0); }
2个进程执行输出。然后开另外一个终端,kill掉父进程,
子进程会继续执行,但父进程会变为1,不是此程序的父进程了。
在console中按ctrl+c,那是会给当前所有的会话中的进程发信号。
所以要用kill,但kill掉父进程后,再用ctrl+c也kill不掉子进程的。
也要用kill。但如果先kill掉子进程,再ctrl+c就可以kill掉父进程。
实例二:
#include <stdio.h> #include <unistd.h> #include <sys/types.h> #include <sys/wait.h> #include <stdlib.h> /* 创建一个子进程, 该子进程会执行一个程序 用exec族的函数 */ int main() { //printf("start of main\n"); pid_t id = fork(); if(id < 0 ) { printf("Fork failed \n"); // perror exit(1); } else if(id == 0) { //printf("child pid = %d \n", getpid()); if(execl("./homework","homework",NULL)<0) { perror("execl error!"); exit(1); } } else if(id > 0) { int status; wait(&status); //sleep(1); printf("parent pid = %d \n", getpid()); } exit(0); }
实例三:
#include <stdio.h> #include <stdlib.h> #include <unistd.h> /* 在父进程中创建两个子进程 子进程分别执行不同的内容 然后再回收 */ void fun(void) { printf("all die ~~~\n"); } int main(int argc, char *argv[]) { int i, status; pid_t id, pid1, pid2; printf("%s's pid = %d\n", argv[0], (int)getpid()); pid1 = fork(); if (pid1 < 0) { perror("error to fork pid1\n"); exit(0); } else if (pid1 == 0) { for (i = 0; i < 5; i++) { printf("child 1: pid = %d, ppid = %d\n", (int)getpid(), (int)getppid()); sleep(1); } exit(0); } wait(&status); /*有特殊回收需求的,可以用waitpid<span style="white-space:pre"> </span>wait(&status);等价于waitpid(-1, &status, 0);<span style="white-space:pre"> </span> <span style="white-space:pre"> </span>&status 可用NULL 代替。 如果一个子进程结束时候没有被父进程回收资源,在父进程存在期间,它是作为僵尸进程; 只有父进程结束时候,它由1号进程init收养后,init会回收该僵尸进程资源 references:http://c.biancheng.net/cpp/html/289.html*/ /*id = waitpid(pid1, &status,0);// wait pid1 printf("%d\n", i);*/ /*这里回收资源,然后再fork一个子进程。如果放到最后和第2个子进程一起回收 那输出显示的时候是交替的*/ pid2 = fork(); if (pid2 < 0) { perror("error to fork pid2\n"); exit(0); } else if (pid2 == 0) { for (i = 0; i < 5; i++) { printf("child 2: pid = %d, ppid = %d\n", (int)getpid(), (int)getppid()); sleep(1); } exit(0); } wait(&status); /*id = waitpid(pid2, &status,0);// wait pid2 printf("%d\n", i);*/ //atexit 注册进程正常退出时候的处理程序, 注册的顺序和处理的顺序是相反的 if(atexit(fun)) perror("error1 "); /* 上面思路是,fork一个,父进程处理函数后,再fork一个。 OR:这个思路是先fork一个,然后进入到父进程处理函数里再fork一个。 id=fork(); if(id < 0 )//error else if(id == 0)//child process else if(id > 0)//parent process create fork again id = fork(); if(id < 0 ) // perror else if(id == 0)//child process else if(id > 0)//parent process */ exit(0); }
相关函数介绍:
fork: 用fork创建子进程,
返回值为-1的时候表示没有创建成功
创建成功的话,0是给子进程; 子进程ID返回给父进程
父、子进程共享正文段,不共享数据空间、堆、栈;
子进程也是由父进程调用FORK后的代码开始执行,变量有独立的拷贝
IO缓冲区也有拷贝
写时复制COW ( COPY ON WRITE)
fork创建后,不保证两进程的调用顺序,
也就是根据系统当前环境不同,可能先调用父进程也可能先调用子进程
vfork: 可以保证子进程先调, 直到子进程调用的exit或者是exec后,父进程才运行
vfork产生的子进程是和父进程共用资源,数据和代码都共享
exec 函数族:(令子进程“脱胎换骨”)
调用的exec后,如果启动成功,子进程就被新执行程序替换了,只保留了进程号, 其它都被替换;
启动失败就返回-1
man 3 environ
execl: exec list 用list挨个写cmd
execv: exec v 指针数组写cmd
execlp: execl path 使用系统环境变量PATH对应的路径中去寻找对应的可执行文件
execvp: exec vp
execle: execl env 环境变量,也是用指针数值去写env
execve: exec ve ---- 内核调用
进程的退出:
_exit(0); 必须是自带有刷写io缓存的动作才能显示出来,这个退出函数是不会关闭IO缓冲区的
exit(); 是会处理退出处理函数的,而且会关闭IO缓冲区
孤儿进程:父进程先于子进程结束了,
这个时候子进程就变成孤儿进程,会由init进程接管;
该孤儿进程结束时候,init会自行回收资源
在bash里面调用一个可执行文件./func , func执行完了就会有一个信号SIGCHLD返回给bash
bash 收到信号后,就会显示gec@ubuntu:/mnt/hgfs/94/系统编程/0910/code$
即使现在还有孙子进程,bash也是不管,但是如果孙子进程要打印数据,依旧是在bash窗口里面显示
atexit 注册进程正常退出时候的处理程序, 注册的顺序和处理的顺序是相反的
atexit(func1) in atexit.c
进程同步(回收资源)
在进程结束的时候回收对应资源
如:之前在虚拟内存里面的申请到的堆数据,
如果进程是一直运行并且不断申请内存而不释放, 就会导致内存泄漏;
如果一个子进程结束时候没有被父进程回收资源,在父进程存在期间,它是作为僵尸进程;
只有父进程结束时候,它由1号进程init收养后,init会回收该僵尸进程资源
wait ():
等待子进程结束并回收资源
等待任意一个子进程
waitpid():
有所扩展的wait
#include <sys/wait.h>
pid_t wait(int *stat_loc);
pid_t waitpid(pid_t pid, int *stat_loc, int options);
int status ;
pid_t id;
id = wait(&status); < == > id = waitpid(-1, &status,0);
在waitpid里面的
pid > 0 就是等待具体的一个进程,其进程号为PID
= 0 等待本进程组里任意子进程
= -1 等待任意一个子进程
< -1 , 等待ID为pid绝对值的进程组里的任意一个子进程
option
WNOHANG, 不需要有已结束进程,立刻返回,不会挂起,也就是不等待
WUNTRACED 若进程被暂停,sTop了,立即返回
WCONTINUED :子进程收到SIGCONT立刻返回
进程的终止:
5种正常
从main返回;
return 0;
调用exit函数;
会先执行一些清理处理,包括调用执行处理终止程序,关闭所有标准I/O流等,然后返回内核
调用_exit或_Exit函数;立即进入内核。
最后一个线程从其启动例程返回;
从最后一个线程调用pthread_exit;
3种异常
调用abort; SIGABRT
接到一个信号并终止;ctrl+c ctrl +\
最后一个线程对取消请求作出响应;
实例二:
相关文章推荐
- C++11 并发指南二(std::thread 详解)
- C++_队列的两种实现方法
- C语言的中断信号
- Effective C++ 条款49 了解new handler的行为
- C语言进程间通信
- C++ 笔记
- C++ 注释规范
- 关于C++代码中的#pragma预处理指令
- Effective C++——条款33(第6章)
- 串口调试助手--VC++ 2010 开发
- C++ Primer第九章课后编程问题
- C++中的字符串
- 周易起名方法C语言程序
- C++面向对象
- C++基础知识
- C语言---进制
- C++ 初始化类的常量数据成员、静态数据成员、常量静态数据成员
- C++_简单的链表栈
- C++中this指针用法详解
- [C++] memcopy 和 memmove的区别和实现