Linux进程控制——进程创建与退出

我们在用C语言结尾的时候总是会有return 0,但是有些人并不知道它到底有什么意思
还有在进程状态中让进程使用kill命令能够停下来,这些与进程控制有着密切的关系

1.进程的创建

fork函数能够在代码中创建一个子进程,我们创建子进程的目的就是为了让它完成不同的任务,我们现在需要创建多个子进程该怎么做呢?

 #include 
 #include 
 #include 
 
 #define N 10
 
 void work()
 {
   int i = N;
   while(i--)
   {
     printf("我的id是:%d,我的父进程是:%d\n", getpid(), getppid());
     sleep(1);
   }
 }
 
 int main()
 {
   int i = 0;
   for(i = 0; i < N; i++)
   {
     pid_t id = fork();
     if(id != 0)
     {
       work();
       exit(0);                                                                     
     }
   }
 
 
   return 0;

我们可以看到这个代码的意思,父进程只进行创建子进程的循环,而子进程完成自己的工作后,就会退出,总共会有10个子进程,但是每个进程执行的任务应该是不一样的,那上面的代码还想也不太可以啊。所以:

#include 
#include 
#include 

#define N 10
typedef void (*func)();

void add()
{
  printf("6666666666666666666666666666666666666666666\n");
}

void work()
{
  int i = N;
  while(i--)
  {
    printf("我的id是:%d,我的父进程是:%d, %d\n", getpid(), getppid(), i);
    sleep(1);
  }
}

void child_process(int n, func f)
{

  int i = 0;
  for(i = 0; i < n; i++)
  {
    pid_t id = fork();
    if(id == 0)
    {
      printf("%d:我是一个子进程,我被创建了\n", i);
      f();                                                                                  
      exit(0);
    }
  }
}

int main()
{
  child_process(5, work);
  sleep(5);
  child_process(5, add);

  sleep(100);
  return 0;
}


Linux进程控制——进程创建与退出_第1张图片
可以看到这样的一种格式可以让某些任务做特定的事。而它的结果也更加反映了,进程的调度不单单是由优先级然后按顺序执行的,它有着更复杂的调度方式。

1.进程的退出

一般来说一个程序运行完后状态有三种:

1.代码运行完毕,结果正确
2.代码运行完毕,结果不正确
3.代码异常终止

而我们现在来讨论一下前两点。

1). 代码运行完毕

退出码

我们在使用C语言的时候,总是最后一句是return 0,而且我们也知道上面代码中的exit函数是用来终止一个进程的,它也有参数。而main函数return的返回值,和exit的参数,都是退出码。我们知道一个进程被创建出来是携带着任务的,那我们怎么知道它的任务是否完成了呢?作为用户来说我们或许可以通过显示器上的打印结果来判断这个进程的任务是否完成,而操作系统它就是由退出码来判断的。
在命令行我们可以通过echo $?来查看最近一次推出的进程的退出码。

#include 
#include 
#include 

int main()
{
  printf("hello world\n");
  return 0;                          
}

Linux进程控制——进程创建与退出_第2张图片

#include 
#include 
#include 

int main()
{
  printf("hello world\n");
  return 1;                       
}

Linux进程控制——进程创建与退出_第3张图片
对操作系统而言,退出的值0代表成功,非零代表失败。而非零的情况下,我们就可以根据不同的数值给出不同的错误原因,所以这就有了错误码的出现。

错误码

我们以前还学过一个码,错误码,它是一个常量errno,会捕获最近一次出错的的原因,然后返回对应的数值。它大概的意思就是,它会把最后一次调用系统调用函数或者标准库函数错误的信息存储在一个叫errno的变量里。
Linux进程控制——进程创建与退出_第4张图片
比如文件打开失败的判断。我们打开一个不存在的文件。

#include 
#include 
#include 
#include 
#include 

int main()
{
  FILE* pf = fopen("a.txt", "r");
  if(pf == NULL)
  {
    printf("%d:%s\n", errno, strerror(errno));
    return 1;                                            
  }
  return 0;
}

在这里插入图片描述
我们看到errno的值是2,对应的信息是没有文件或文件夹。
每个错误码都对应着一个错误信息:

#include 
#include 
#include 
#include 
#include 

int main()
{
  int i = 0;
  for(i = 0; i < 300; i++)
  {
    printf("%d:%s\n", i, strerror(i));                          
  }
  return 0;
}

Linux进程控制——进程创建与退出_第5张图片
Linux进程控制——进程创建与退出_第6张图片
我们看到总共有133个错误信息。而这我们也可以自己定义,也就是代码中添加个数组的事。
退出码和错误码的区别就是,退出码说明一个进程的退出原因,错误码是说明系统调用函数或库函数的调用情况

2). 代码异常终止

我们在Windows下运行代码的时候经常会遇到,突然就会弹出类似于这样一个框:

Linux进程控制——进程创建与退出_第7张图片

例如除以零,栈溢出,野指针的那种情况。
而在linux中野指针就是段错误:

int main()
{
  int* a = NULL;
  *a = 10;               
  return 0;
}

在这里插入图片描述
除以零是这种:

在这里插入图片描述
这种情况就是代码出异常,操作系统给进程发了个信号,让它以某种原因终止了。我们也知道Linux中的信号:
Linux进程控制——进程创建与退出_第8张图片
我们现在运行一个程序,然后用段错误的信号来终止它:
Linux进程控制——进程创建与退出_第9张图片
也说明了我们上面说的是正确的。
进程出异常,本质是进程收到了对应的信号,自己终止了,所以一个进程是否出异常,我们只要看有没有收到信号即可
一旦异常一般都是代码没跑完,退出码也就没有意义了
所以子进程退出的时候,父进程只需要知道两个数字即可

你可能感兴趣的:(linux,c语言)