C语言简单进程
来源:互联网 发布:热量计算软件 编辑:程序博客网 时间:2024/04/20 03:25
进程:
进程是正在运行的程序的实例
进程是一个具有独立功能的程序关于某个数据集合的一次运行活动
是系统进行(资源分配和调度)的基本单位,是操作系统结构的基础
是一个动态的概念,是一个活动的实体
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"); // perrorexit(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"); // perrorexit(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 )//errorelse if(id == 0)//child processelse if(id > 0)//parent process create fork againid = fork();if(id < 0 ) // perrorelse if(id == 0)//child processelse 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语言简单进程
- c语言进程池的简单实现
- C语言实现简单的守护进程及信号处理
- C语言枚举进程,实现一个简单的内存补丁
- C语言进程结构
- 【语言-C#】进程处理
- C语言-LINUX进程
- C语言-WIN32进程
- c语言学习进程
- Linux C语言 进程
- C语言---多进程
- 【语言-C++】C++、C 创建挂起进程
- c语言简单应用
- C语言简单认识
- C语言简单摘要
- C语言简单编程
- C语言简单程序
- C语言简单程序
- Java 运算符优先级以及一些小题
- UGUI 音效
- 【LeetCode】Swap Nodes in Pairs
- 版本控制系统
- Hadoop/spark安装实战(系列篇5) scala安装
- C语言简单进程
- G.703接口和E1接口区别
- Dojo 入门
- Delphi调用C#写的webservice
- ACtivity跳转
- Android学习记录:获取联系人
- SqliteDB 操作数据库
- Linux启动过程详解
- VS2010在同一个解决方案中有多个工程是,点运行会一直运行最开始的工程,有什么办法解决吗?