代码:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
/*************基本的函数API********************
1-pid func
pid_t getpid(void)
pid_t fork(void)
fork函数创建的字进程是父进程的副本,执行的是与父进程完全相同的程序,为了让fork子进程能够运行另外的程序,需要用的exec函数 2-exec func
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,const char *arg[])
int execvp(const char *file,const char *arg[])
int execve(const char *file,const char *arg, char * const envp[]) 3-system func
int system(const char *string)
**********************************************/
#define Test_fork 0
#define Test1 0
#define Test2 1 #define Test_exec 1
#define Test_syst 0 static int idata = ; int main(void)
{
#if Test_fork
pid_t pid0,pid1;
pid0 = fork();
pid1 = fork();
printf("Fork's PID0 = %d\nPID1 = %d\n",pid0,pid1);
//printf("PID = %d\n", getpid());
#endif #if Test1
int istack = ;
pid_t childPid;
printf("Test Fork!\n");
fflush(stdout);
// The parent's printf's buffer content will be copy to child-process's buffer and being stdout to the file object but not the screen! switch(childPid = fork())
{
case -: exit();
case : idata *= ; istack *= ; break;
default: sleep(); break;
} printf("PID=%ld %s idata=%d istack=%d \n",(long)getpid(),(childPid == )?"(child)":"(parent)",idata,istack);
exit(EXIT_SUCCESS);
#endif #if Test2
pid_t pid0,pid1;
pid0 = fork();
printf("PID=%ld %s\n",(long)getpid(),(pid0 == )?"(child0)":"(parent)");
pid1 = fork();
printf("PID=%ld %s\n",(long)getpid(),(pid1 == )?"(child1)":"(parent)");
exit(EXIT_SUCCESS);
#endif #if Test_exec
if( == fork())
{
int ret;
ret = execlp("ls","ls","-l", NULL);
return ;
}
#endif #if Test_syst
int ret;
ret = system("ls -al");
printf("OK!\n");
return ;
#endif return ;
}

主要说明上述程序中fork的相关内容,纪录在此,方便后面理解!

fork()函数用来创建一个新的进程,新创建的这个进程的data数据段,stack堆栈段等进程基本的内容以及当前程序状态指针PC-point也完全和父进程相同!也就是说fork创建的子进程是父进程的副本,新创建的这个进程,Linux会为它分配对应的内存页来保存与父进程完全相同data、stack、进程运行到的目前的状态。但是对于程序段text,父进程与子进程是共享的!对于Test2程序的运行结果如下所示:

对上述的结果分析如下所示:

 如图所示,每一个fork下面只要存在fork那么就会产生多级的子进程。

1、如图中所示的关系,P是C0的父进程,也是C1的父进程,C0是C2的父进程。

2、在这样的关系当中,所有进程的状态都有所不同,再运行到fork0的位置处,P和C0的PC指针状态相同,C0进程不会再去运行fork0上面的所有程序,同样的C2不会运行fork1上面的所有程序,C1不会运行fork1上面的所有程序

     ,这样也就是子父进程的状态相同的意思!

3、图中的printf表示该进程PC指针知道该位置处需要运行的任务,总共运行了6条printf,这和我们的演示结果相同,printf("PID=%ld %s\n",(long)getpid(),(pid1 == 0)?"(child1)":"(parent)");

      这样的代码会帮我们区分子父进程并打印出当前进程的PID!

4、由于所有进程包括子父进程之间都会存在竞争关系,所以运行的结果每次都会不同,同时PID的数值也会有所不同(对于多核心CPU来说,进程可能存在同步运行的情况!)。

5、一定要注意,fork在父进程运行过程中的返回值是子进程真实的PID number,pid_t pid = fork(),这样在父进程中获取的pid是真实的进程ID>0,获取失败则为-1,但是在进入子进程之后,实际上这个值是0,

      所以一对子父进程中的pid的值不同!这很重要!

6、子父进程之间的数据交换可以使用信号量的方式来同步和互斥!#include <singnal.h>

7、子父进程不共享数据段,堆栈段,进程PCB内容,但是共享不可改写的代码段!所以数据的修改不是同步的!但是对于新创建的文本等字符设备上的文件对象,子父进程存在竞争关系,需要同步和互斥来保证数据的正确性!

8、注意在Test1程序当中,我们在printf之后添加了fflush函数,对printf函数中的缓冲内容进行了刷新,在重定向到文件过程中就不会出现fork的子进程的输出缓冲内容了,不然结果会不同:

9、当父进程先于子进程终止时,子进程变成了孤儿进程,操作系统统一为其找到一个 PID为 1 的 init(操作系统最先运行的进程),接管此进程。

进程其他相关API:

1、使用wait()函数等待子进程完成操作,或者使用waitpid()

pid_t pid,pid_end;
pid = fork();
if(pid == )
{
printf("ChildProcess:%ld\n",(long)getpid());
sleep();
}
else
{
printf("ParentProcess:%ld\n",(long)getpid());
}
pid_end = wait(NULL);
printf("The ChildProcess:PID %d is Stopped!\n",pid_end);
exit(EXIT_SUCCESS);

运行结果如下所示:

Linux下C语言的进程控制编程的更多相关文章

  1. Linux下C语言的socket网络编程

    关于详细的服务器建立的步骤以及相关的socket套接字的知识我已经在python socket编程的文章中提到过了,大家可以参看那一篇博客来历接socket套接字编程的内容,由于要是用C相关的API所 ...

  2. linux下C语言多线程编程实例

    用一个实例.来学习linux下C语言多线程编程实例. 代码目的:通过创建两个线程来实现对一个数的递加.代码: //包含的头文件 #include <pthread.h> #include ...

  3. Linux下C语言编程实现spwd函数

    Linux下C语言编程实现spwd函数 介绍 spwd函数 功能:显示当前目录路径 实现:通过编译执行该代码,可在终端中输出当前路径 代码实现 代码链接 代码托管链接:spwd.c 所需结构体.函数. ...

  4. Linux基础与Linux下C语言编程基础

    Linux基础 1 Linux命令 如果使用GUI,Linux和Windows没有什么区别.Linux学习应用的一个特点是通过命令行进行使用. 登录Linux后,我们就可以在#或$符后面去输入命令,有 ...

  5. LINUX下C语言编程基础

    实验二 Linux下C语言编程基础 一.实验目的 1. 熟悉Linux系统下的开发环境 2. 熟悉vi的基本操作 3. 熟悉gcc编译器的基本原理 4. 熟练使用gcc编译器的常用选项 5 .熟练使用 ...

  6. LINUX下C语言编程调用函数、链接头文件以及库文件

    LINUX下C语言编程经常需要链接其他函数,而其他函数一般都放在另外.c文件中,或者打包放在一个库文件里面,我需要在main函数中调用这些函数,主要有如下几种方法: 1.当需要调用函数的个数比较少时, ...

  7. Linux下C语言编程基础学习记录

    VIM的基本使用  LINUX下C语言编程 用gcc命令编译运行C语言文件 预处理阶段:将*.c文件转化为*.i预处理过的C程序. 编译阶段:将*.i文件编译为汇编代码*.s文件. 汇编阶段:将*.s ...

  8. 【转】Linux基础与Linux下C语言编程基础

    原文:https://www.cnblogs.com/huyufeng/p/4841232.html ------------------------------------------------- ...

  9. 使用c语言实现在linux下的openssl客户端和服务器端编程

    使用c语言实现在linux下的openssl客户端和服务器端编程 摘自:https://www.cnblogs.com/etangyushan/p/3679457.html 前几天组长让我实现一个使用 ...

随机推荐

  1. 部署apache-tomcat环境

    软件体系: C/S:客户端/服务器,例如qq等app都属于C/S体系,除了编写服务端代码还需要编写客户端 优点:展现比较好,客户端会承受一点运算压力,安全性比较好 缺点:更新服务端的同时还需要更新客户 ...

  2. 40)django-常用过滤器

    一.形式:小写 {{ name | lower }} 二.过滤器是可以嵌套的,字符串经过三个过滤器,第一个过滤器转换为小写,第二个过滤器输出首字母,第三个过滤器将首字母转换成大写 标签 {{ str| ...

  3. Confluence 6 使用 Apache 和 mod_proxy 的基本配置

    在这些示例中,我们使用下面的信息: http://www.example.com/confluence - 你计划使用的 URL http://example:8090/ - Confluence 当 ...

  4. python之内置模块random(转载)

    转载自http://www.cnblogs.com/wcwnina/p/9281334.html random.seed(a=None, version=2) # 初始化伪随机数生成器,若种子a相同, ...

  5. Data Preprocess

    本文试图解决一个问题,即我们自定义的数据如何训练模型?初识深度学习,我们接触手写数字识别模型,但是批次数据是mnist已经定义好的,我们现在有自己的图片如何做成批次进行训练模型. 现在我们将准备好的原 ...

  6. PDF文件如何标注,怎么使用PDF标注工具

    我们在使用文件的时候需要给文件的部分添加标注,能够更加直观的了解文件,但是有很多小伙伴们对于PDF文件怎么添加标注都不知道,也不知道PDF标注工具要怎么使用,那么下面就跟大家分享一下怎么使用PDF标注 ...

  7. Python获取当前时间及时间转换(datetime)

    datetime是Python处理日期和时间的标准库 获取当前时间 import datetime day = datetime.datetime.now() day2 = datetime.date ...

  8. 创建WIFI热点

    @echo off:beginecho 笔记本做无线WiFi程序(首次使用请先设置WiFi帐户.)echo 1.设置WiFi帐户,请按1echo 2.开启WiFi功能,请按2echo 3.闭关WiFi ...

  9. 如何在EXCEL中找出第一列中不包含的第二列数据

    1.找出第一列中不包含的第二列数据:=IFERROR(VLOOKUP(A:A,B:B,1,0),"无") 2.A列相同,B列相加:=SUMIF(G:G,G1,J:J)

  10. C++ Primer 笔记——命名空间

    1.我们既可以用 using 声明整个空间,也可以声明部分名字. using namespace std; using std::cout; 2.头文件不应包含 using 声明,因为头文件会拷贝到所 ...