浅析fork函数、exec函数和pthread函数

文章最后更新时间为:2018年08月14日 10:48:32

1、fork函数,exec函数和pthread函数的机理

在linux中,每个进程都使用一个唯一的整数形式的进程标识符来标识。

1.1 fork()

Fork()函数是创建新进程的函数,即通过fork()系统调用,可创建新进程。新进程复制原来进程的地址空间,这种机制允许父子进程之间相互通信。两个进程都继续执行系统调用fork()函数之后的指令。但是不同的是,对于新创建的进程,系统调用fork()之后的返回值为0,对于原来的父进程,返回值大于0,如果创建新进程失败,则返回一个负值。使用fork函数得到的子进程从父进程继承了整个进程的地址空间,包括:进程上下文、进程堆栈、内存信息、打开的文件描述符、信号控制设置、进程优先级、进程组号、当前工作目录、根目录、资源限制、控制终端等。

1.2 exec()

exec()函数用于将一个进程替换为一个新的进程。exec函数的函数执行成功后不会返回,因为调用进程的实体,包括代码段,数据段和堆栈等都已经被新的内容取代,只有进程ID等一些表面上的信息仍保持原样。调用失败时,会设置errno并返回-1,然后从原程序的调用点接着往下执行。Exec()本身并没有创建新进程,只是将原进程分配了新的数据段和堆栈段。

Exec()函数一般用于系统调用fork()函数之后,新进程会使用exec()函数来代替父进程的内存空间系统通过调用exec()函数将二进制文件装入内存,并开始执行。在这个过程中,我们可以改变创建的新进程来执行一个新的程序。

1.3 pthread

pthread和上述两个函数不同,pthread和线程有关。Pthread是为线程创建和同步定义的API,在一个进程中可以有多个线程,每个线程都有自己的栈和调度信息还有私有信息等。

Pthread含有很多函数:

  • pthread_t 是pthread的线程ID
  • pthread_create()用于创建新的线程
  • pthread_equal()用于比较两个线程id是否相等
  • pthread_self() 用于获取当前线程的id
  • pthread_exit() 线程调用该函数主动退出线程
  • pthread_join() 用于线程同步,以阻塞的方式等待指定线程结束

通过上述函数我们可以对线程进行控制,也可以创建新的线程。

2、举例说明:

2.1 需求:

  • 1.进程A 创建子进程B
  • 2.子进程B与父进程A分别对应不同的exe(进程A打印Hello word, 进程B实现sum累加)
  • 3.进程B具有两线程,其中主线程创建新的线程来实现sum累加(从1累加到参数x)

    2.2 代码

    1、 main_process.c

    #include<stdio.h>
    #include<sys/types.h>
    #include<unistd.h>
    int main(int argc,char ** argv){
         pid_t pid;
      pid=fork();
      if(pid<0) // error
      {
          printf("there have something wrong\n");
          
      }
      if(pid>0)  // father
      {
          printf("this is main process\n");
          
      }
      if(pid==0) // son
     {    
          printf("this is new processs");
          // execl( "/root/fork/2","10",NULL);
          if( execl( "/root/fork/new_process",argv[1],NULL) < 0)
          {
            perror("execv error ");
          }
      }
      return 0;
    }

    2、 new_process.c

     #include<stdio.h>
    #include<pthread.h>
    int sum;
    void *runner(void *param);
    int main(int argc,char *argv[])
    {    
      printf("this is new process");
      pthread_t tid; // the thread identifuer
      pthread_attr_t attr; // set thread attributes
      pthread_attr_init(&attr); // default attributes
      pthread_create(&tid,&attr,runner,argv[1]);// create new thread
      pthread_join(tid,NULL); 
      printf("the sum is %d\n",sum);
    }
    
    void *runner(void *param)
    {
       int i,upper=atoi(param);
      sum=0;
      for(i=0;i<=upper;i++)
          sum=sum+i;
      pthread_exit(0);
    }

    2.3 代码分析:

  • 主程序进入main函数之后,创建一个进程,给这个进程分配内存和该进程数据段和堆栈所需的物理空间。
  • 之后主函数使用fork()函数创建新进程,新进程和原进程使用相同的内存,子进程的代码段、数据段、堆栈都是指向父进程的物理空间。
  • 父进程输出‘helloworld‘,子进程使用exec函数调用new_process.c,这时进程的数据段,堆栈等内容都被修改,从而我们设立新进程为new_process程序。
  • 在执行new_process函数时,我们使用Pthread函数创立了一个新的线程,该线程与原线程享用相同的公用数据,进程信息。同时也有自己的独立数据。在代码里面,新线程实现累加功能,并把累加的结果赋给共用数据sum。
1 + 3 =
快来做第一个评论的人吧~