栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

Linux进程相关概念

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Linux进程相关概念

目录

一.创建进程函数fork  

二.vfork创建进程

三.进程退出

四.exec族函数

五.孤儿进程与僵尸进程

六.system函数

七.popen函数


什么是进程?

进程是程序的一次运行活动,通俗点意思是程序跑起来了,系统中就多了一个进程


如何查看系统中有哪些进程?

a.使用ps指令查看实际工作中,配合grep来查找程序中是否存在某一个进程

b.使用top指令查看,类似windows任务管理器


什么是进程标识符?

每个进程都有一个非负整数表示的唯一ID,叫做pid,类似身份证·

Pid=0:  称为交换进程(swapper)-------作用:进程调度

Pid=1:init进程  -------作用:系统初始化

编程调用getpid函数获取自身的进程标识符

getppid获取父进程的进程标识符


什么叫父进程,什么叫子进程

进程A创建了进程B,那么A叫做父进程,B叫做子进程,父子进程是相对的概念,理解为人类中的父子关系。


C程序的存储空间是如何分配?

正文段:存放的代码如switch,if,else,for等

数据段:初始化过的变量

bss段:在函数外未被初始化的变量

堆:如malloc申请空间就在堆中申请

栈:函数调用,函数调用产生的局部变量


一.创建进程函数fork  
SYNOPSIS
       #include 
       pid_t fork(void);

fork函数调用成功,返回两次

返回值为0,      代表当前进程是子进程

返回值非负数,代表当前进程为父进程(且返回值为新进程的pid)

调用失败,返回-1

demo

#include 
#include 
#include 

int main()
{
      pid_t pid;
      pid_t pid2;
      pid_t retpid;

      pid = getpid();
      printf("this is before pid:%dn",pid);
      retpid = fork();

      pid2 = getpid();
      printf("this is after pid:%dn",pid2);

      if(pid > 0){
        printf("this is father pid,return is:%dn",retpid);
      }
      else {
        printf("this child pid,return is%dn",retpid);
     }
      return 0;
}

运行结果:


二.vfork创建进程

关键区别一:vfork 直接使用父进程存储空间,不拷贝。

关键区别二:vfork保证子进程先运行,当子进程调用exit退出后,父进程才执行。

demo

#include 
#include 
#include 
#include 

int main()
{
   pid_t pid;
   int cnt;

   pid = vfork(); //用vfork创建进程

        if(pid > 0){
                while(1){
                printf("this is father print,pid is %dn",getpid());
                sleep(1);
                }
        }
        if(pid == 0){
            while(1){
                printf("this is child print,pid is %dn",getpid());
                sleep(1);
                cnt++;
                if(cnt == 3){
                exit(0);  //当cnt=3,退出进程
             }
        }
   }
   return 0;
}

三.进程退出

函数原型

SYNOPSIS
       #include 

       void exit(int status);

SYNOPSIS
       #include 

       void _exit(int status);

       #include 

       void _Exit(int status);

正常退出

1.Main函数调用return

2.进程调用exit(),标准c库

3.进程调用_exit()或者_Exit(),属于系统调用

异常退出

1.调用abort

2.当进程收到某些信号时,如ctrl+C

3.最后一个线程对取消(cancellation)请求做出响应

补充:进程最后一个线程返回;最后一个线程调用pthread_exit


父进程等待子进程退出

创建子进程之后,我们需要判断子进程是否“干完活”可以通过回收子进程的退出状来判断。子进程退出状态不被收集,变成僵死进程(僵尸进程)

父进程通过下面的api来收集子进程的退出状态。

wait

SYNOPSIS
       #include 
       #include 

       pid_t wait(int *status);
      

status参数

是一个整型数指针

非空:子进程退出状态放在它所指向的地址中。

空:   不关心退出状态

status判断子进程如何退出状态

WIFEXITED(status)为非0 ,进程正常结束
WEXITSTATUS(status)如上宏为真,使用此宏,获取进程退出状态的参数
WIFSIGNALED(status)为非0,进程异常退出
WTERMSIG(status)如上宏为真,使用此宏,取得使进程种植的那个信号的编号

waitpid

   pid_t waitpid(pid_t pid, int *status, int options);

函数作用:同wait函数,区别在于可以调用者不阻塞。

pid

pid == ‐1 等待任意子进程

pid > 0    等待其进程ID与pid相等的子进程

pid == 0  等待其组ID调用调用进程组ID的任一子进程

pid < -1   等待其组ID等于pid绝对值的任一子进程

status同上
options设置为WNOHANG,函数非阻塞,设置为0,函数阻塞

返回值: >0 :返回清理掉的子进程ID ‐1 :回收失败,无子进程 如果为非阻塞 =0 :参数3为WNOHANG,且子进程正在运行

孤儿进程

父进程如果不等待子进程退出,在子进程之前就结束了自己的“生命”,此时子进程叫做孤儿进程

Linux避免系统存在过多孤儿进程,init进程收留孤儿进程,变成孤儿进程的父进程

demo

#include 
#include 
#include 
#include 
#include 

 int main()
{
 pid_t pid;

 int cnt = 0;
 int status = 0;

 pid = fork();

 if(pid>0)
 {
   wait(&status);
   printf("child quit,child status is %dn",WEXITSTATUS(status));
   while(1)
   {
   printf("cnt=%dn",cnt);
   printf("this father pid print,pid is=%dn",getpid());
   sleep(1);
   }
 }
 else if(pid==0)
 {
   while(1)
   {
     printf("this children pid print,pid is=%dn",getpid());
     sleep(1);
     cnt++;
     if(cnt==5){
        exit(3);
      }
    }
  }
     return 0;
 }

四.exec族函数
SYNOPSIS
       #include 

       extern char **environ;

       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, char *const argv[]);
       int execvp(const char *file, char *const argv[]);
       int execvpe(const char *file, char *const argv[],char *const envp[]);

作用

我们用fork函数创建新进程后,经常会在新进程中调用exec函数去执行另外一个程序。当进程调用exec函数时,该进程被完全替换为新程序。因为调用exec函数并不创建新进程,所以前后进程的ID并没有改变。

返回值

exec函数族的函数执行成功后不会返回,调用失败时,会设置errno并返回-1,然后从原程序的调用点接着往下执行。

参数说明

path:可执行文件的路径名字

arg:可执行程序所带的参数,第一个参数为可执行文件名字,没有带路径且arg必须以NULL结束

file:如果参数file中包含/,则就将其视为路径名,否则就按 PATH环境变量,在它所指定的各目录中搜寻可执行文件。

它们的一般规律如下

l (list) 命令行参数列表

p (path) 搜素file时使用path变量

v (vector) 使用命令行参数数组

e (environment) 使用环境变量数组,不使用进程原有的环境变量,设置新加载程序运行的环境变量

demo

//文件execl.c
#include 
#include 
#include 
//函数原型:int execl(const char *path, const char *arg, ...);

int main(void)
{
    printf("before execln");
    if(execl("./bin/echoarg","echoarg","abc",NULL) == -1)
    {
        printf("execl failed!n");      
    }
    printf("after execln");
    return 0;
}
//文件echoarg.c
#include 

int main(int argc,char *argv[])
{
    int i = 0;
    for(i = 0; i < argc; i++)
    {
        printf("argv[%d]: %sn",i,argv[i]); 
    }
    return 0;
}

五.孤儿进程与僵尸进程

孤儿进程: 一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。孤儿进程将被init进 程(进程号为1)所收养,并由init进程对它们完成状态收集工作

僵尸进程: 一个比较特殊的状态,当进程退出父进程(使用wait()系统调用)没有读取到子进程退出的返回代码时就会产生僵尸进程。僵尸进程会在以终止状态保持在进程表中,并且会一直等待父进程读取退出状态代码。

六.system函数

函数原型

SYNOPSIS
       #include 

       int system(const char *command);

system()函数的返回值如下:
成功,则返回进程的状态值;
当sh不能执行时,返回127;
失败返回-1;

demo

#include 
#include 
#include 
#include 
#include 

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

    while(1){
    printf("please input datan");
    scanf("%d",&data);

    if(data == 1)
   {
     pid = fork();
       if(pid == 0)
     {
        system("./changedata text.config");
     }

       if(pid>0)
     {
       wait(NULL);
     }
   }
   else{
   printf("wait do nothingn");
   }
  }

   return 0;
}

七.popen函数

函数原型

SYNOPSIS
       #include 

       FILE *popen(const char *command, const char *type);

比system在应用中的好处:可以获取运行的输出结果

popen的好处:可以将指令的执行结果存入字符串中或存入文件中

demo

#include 
#include 
#include 

int main()
{
   char ret[1024] = {0} ;
   FILE *fp;

   fp =  popen("ps","r");
   int n_read = fread(ret,1,1024,fp);
   printf("read %d byte,ret=%sn",n_read,ret);

   return 0;
}

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/966040.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号