Linux进程学习(fork,exec族,popen函数)

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

关于Linux进程的学习就是去理解进程是什么,并且知道在Linux下一些关于进程的一些概念和常见用发,本人以下是通过fork函数和exec族函数来理解学习线程的


提示:以下是本篇文章正文内容,下面案例可供参考

一、进程的基本概念?

1.什么是程序,什么是进程有什么区别?
首先进程是静态动态概念,程序是动态概念,一个软件不点开就是程序,一点开就是进程。
2.如何查看系统中有哪些进程?
a.使用ps指令查看,一般是结合这aux和grep一起使用。实例:ps -aux|grep init
b.也有一种类似window任务管理器的指令是top查看指令可以查看Linux中各个线程的cpu和磁盘的占用率
3.什么是进程标识符,什么是父子进程?
进程A创建了进程B,那么A叫做父进程,B叫做子进程。进程标识符是一个非负整数相当于进程的身份证,每一个进程都有自己的pid标示符,其中函数getpid()表示获取当前进程pid编号,getppid()表示获取父进程标识符。
4.c程序的存储空间如何分配
如图在这里插入图片描述
高地址:这里是一些环境变量,还有在main函数里面写的argc和argv。
栈: 在main函数里面调用的函数返回地址,在该调用函数里的局部变量也是属于栈
堆: calloc和malloc的返回地址(动态存储分配)就是堆
bss段(未初始化的数据):就是函数外未初始化的全局变量的地址
数据段(初始化的数据):就是在main函数中和函数外给予初始化的变量
低地址正文(代码段):就是一些c语言语法之类的,比如if,for,switch一些算法等等

二、fork和vfork

1.fork函数介绍

fork函数调用后fork后面代码会调用两次,一次为父进程调用一次为子进程调用。且fork会有三个参数0和非负整数还有-1,其中非负整数为父进程,0为子进程,-1为返回错误。并且子进程会copy一份父进程的代码共享代码,子进程中对变量进行改变时不会影响到父进程(这里称为写时拷贝)以下是代码验证。
代码示例:

#include <sys/types.h>
#include <unistd.h>
#include<stdio.h>
void delay(int i)
{
    while(i--);
}

int main()
{
    int a=10;
    pid_t  pid1=0;
    pid_t  pid2=0;
    pid_t  Parameter;

    printf("在fork之前的pid=%d\n",getpid());
    Parameter=fork();
    printf("在fork之后的pid=%d\n",getpid());

    if(Parameter>0)
    {
      printf("这是父进程pid=%d\n",getpid());
      delay(1000000);
    }
    else if(Parameter==0)
    {
      printf("这是子进程pid=%d\n",getpid());
      a=a+10;
    }

    printf("这里a=%d\n",a);

return 0;
}

结果

在fork之前的pid=33043
在fork之后的pid=33043
这是父进程pid=33043
在fork之后的pid=33044
这是子进程pid=33044
这里a=20
这里a=10

这里完全说明了fork函数之前的代码只执行一次并且为父进程执行,fork后执行两次,并且说明父子进程虽然是共享代码,但是子进程中变量a改变数据时不会影响到父进程的变量a的值(完全说明了写时拷贝)并且这里加的延时函数是怕子进程的变量没附上值父进程就退出。

2.vfork函数介绍

首先vforkfork相比有两个非常不同的地方
1.vfork中子进程不会拷贝父进程的存储空间,而是直接去使用
2.vfork保证子进程会先执行,当子进程调用exit退出后,父进程才执行。
代码如下(示例):

#include <sys/types.h>
#include <unistd.h>
#include<stdio.h>
#include <stdlib.h>

int main()
{
        int cnt=0;
        pid_t pid;

        pid=vfork();

        if(pid>0)
        {
                while(1)
                {
                        printf("this is father:%d,cnt=%d\n",getpid(),cnt);
                        sleep(1);
                }
        }
        if(pid==0)
        {
                while(1)
                {
                        cnt++;
                        printf("this is son:%d,cnt=%d\n",getpid(),cnt);
                        if(cnt==5) exit(-1);

                }
        }

}

**结果:

this is son:34382,cnt=1
this is son:34382,cnt=2
this is son:34382,cnt=3
this is son:34382,cnt=4
this is son:34382,cnt=5
this is father:34381,cnt=5
this is father:34381,cnt=5
this is father:34381,cnt=5
this is father:34381,cnt=5
this is father:34381,cnt=5
^Z

从这个结果来看,vfork()的特性完全可以体现出来,先是子进程执行且用exit()结束后,再是父进程执行,并且它们之间是同一块内存

3.进程退出

正常退出
1.main函数调用return
2.进程调用exit(),这是标准c库
3.进程调用_exit()或者_Exit(),属于系统调用
补充:进程最后一个线程返回。最后一个线程调用pthtead_exit
异常退出
1.调用abort.
2.收到某种信号,如^c.

父进程等待子进程退出

NAME
       wait, waitpid, waitid - wait for process to change state

SYNOPSIS
       #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);

如果子进程退出状态不被收集,将变成僵尸进程(linux上用ps指令显示Z+)。如果不想子进程变成僵尸进程可以在父进程中使用wait()函数去等待状态。
为什么要去等待子进程退出
首先创造子进程的目的是去干活,如果活干完了,当然需要子进程退出但是子进程退出后的状态,是干完活退出的还是异常退出的这里就需要去判断相应的状态值了。

三.exec族函数

这篇博文exec族函数

四.popen函数

popen() 函数 用 创建管道 的 方式启动一个 进程, 并调用 shell. 因为 管道是被定义成单向的, 所以 type 参数 只能定义成 只读或者 只写, 不能是 两者同时, 结果流也相应的 是只读 或者 只写.

#include <stdio.h>
FILE *popen(const char *command, const char *type);
int pclose(FILE *stream);

popen 通过type是r还是w确定command的输入/输出方向,r和w是相对command的管道而言的。r表示command从管道中读入,w表示 command通过管道输出到它的stdout,popen返回FIFO管道的文件流指针。pclose则用于使用结束后关闭这个指针。

代码示列

#include<stdio.h>
#include <string.h>

int main()
{
  FILE * stream;
  FILE * wstream;
  char buf[1024];

  memset(buf,0, sizeof(buf));//避免遇到乱码,初始化文件夹
  stream=popen("ls -l","r");
  wstream=fopen("opentest.txt","w+");//建立一个可读可写的文件
  fread(buf,sizeof(char),sizeof(buf),stream);//将oppen中获取到的数据流读到buf中
  fwrite(buf,1,sizeof(buf),wstream);//写入到文件夹中

  return 0;

}

总结

本文就是简单介绍了linux中进程的概念和基本用法,其中fork和popen还是用的比较多。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值