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

7.linux进程系统调用

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

7.linux进程系统调用

一、fork()机制

        fork()函数用于进程创建,定义如下:

所需头文件#include // 提供类型pid_t的定义
#include
函数原型pid_t fork(void);
函数返回值0: 子进程   大于0的整数为子进程的PID:父进程   -1:错误

fork()函数示例代码:

#include
#include
#include


int main(void)
{
    pid_t pid;  //保存fork函数返回值

    printf("本进程的PID = %dn",getpid());
    pid = fork();

    if(pid == -1) {
        printf("error fork() n");
    }
    else if(pid > 0) {  //父进程
        printf("pid = %d, father id = %d n",pid,getpid());
    }
    else {  //子进程
        printf("pid = %d, chile id = %d n",pid,getpid());
    }
    
    return 0;
}

 运行结果如下:

        从上图可以看出,首先进程执行打印了本进程的pid = 4596,随后执行fork()函数创建子进程,由于fork()函数有两个返回值分别对应父进程和子进程,因此加上if条件判断。

        在父进程中打印了pid返回值4597,和父进程pid=4596,fork的返回值4597对应的就是子进程的pid.
        在子进程中打印了pid返回值0,和子进程pid = 4597。


        使用fork函数得到的子进程从父进程的继承了整个进程的地址空间,包括:进程上下文、进程堆栈、内存信息、打开的文件描述符、信号控制设置、进程优先级、进程组号、当前工作目录、根目录、资源限制、控制终端等。

        调用fork()后,子进程如果完全拷贝了父进程的数据段,堆,栈内存。(通常在:fork()之后,子进程往往会立马调用exec系列的函数,来执行一个新的不同的程序),那么会产生较高的性能开销。因为如果子进程拷贝父进程的数据段,堆,栈内存,那么又会立马调用exec系列函数覆盖掉刚刚拷贝的内存,那么这么做是毫无意义的。因此Linux引进了写时拷贝(copy - on - write)的技术。写时拷贝可以避免拷贝大量根本就不会使用的数据。因此可以看出写时拷贝极大提升了Linux系统下fork函数运行地性能。

写时拷贝指的是子进程的页表项指向与父进程相同的物理页,这也只需要拷贝父进程的页表项就可以了,不会复制整个内存地址空间,同时把这些页表项标记为只读。如果父子进行都不对页面进行操作,那么便一直共享同一份物理页面。只要父子进程有一个尝试进行修改某一个页面,那么就会发生缺页异常(page fault)。那么内核便会为该页面创建一个新的物理页面,并将内容复制到新的物理页面中,让父子进程真正地各自拥有自己的物理内存页面,并将页表中相应地页表项标记为可写。
写时拷贝父子进程修改某一个页面前后变化如下图所示:

示例代码:

#include
#include
#include
#include


int main()
{
    pid_t pid;
    int cnt=0;
    printf("cnt=%dn",cnt);
    pid = fork();
    if(pid >0){ //父进程
        sleep(1);
        printf("cnt=%dn",cnt);
        printf("this is father print pid is %dn",getpid());
    }
    else if(pid == 0){ //子进程
        printf("this is child print pid is =%dn",getpid());
        cnt++;
        }

    return 0;
}

        运行结果如下:

可以看出子进程修改cnt值,其实修改的是内核新创建的物理页面。 

二、exec函数族

        如果一个进程想执行另一个程序,那么它就可以调用fork函数新建一个进程,然后调用任何一个exec函数使子进程重生。exec函数通常在fork()函数创建的子进程中调用,可以实现去执行新的程序,清空原来的堆栈区、代码区和数据区,让新的可执行程序完全替代现有的资源

        语法定义如下:

所需头文件 #include 
函数原型 int execl(const char *path, const char *arg, ...);
int execv(const char *path, char *const argv[]);
int execle(const char *path, const char *arg, ..., char *const envp[]);
int execve(const char *path, char *const argv[], char *const envp[]);
int execlp(const char *file, const char *arg, ...);
int execvp(const char *file, char *const argv[]);
函数返回值 -1:出错

      ① 第一个参数是带路径的执行码(execlp、execvp函数第一个参数是无路径的,系统会根据PATH自动查找然后合成带路径的执行码);
      ② 第二个是不带路径的执行码,执行码可以是二进制执行码和Shell脚本。

 

调用举例如下:

#include 
#include 
#include 
#include 
#include 
 
 int main(int argc, char *argv[])
 {
   //以NULL结尾的字符串数组的指针,适合包含v的exec函数参数
   char *arg[] = {"ls", "-a", NULL};
   
   
   if( fork() == 0 )
   {
     // in clild 
     printf( "1------------execl------------n" );
     if( execl( "/bin/ls", "ls","-a", NULL ) == -1 )
     {
       perror( "execl error " );
       exit(1);
     }
   }
   
   
   if( fork() == 0 )
   {
     // in child 
     printf("2------------execv------------n");
     if( execv( "/bin/ls",arg) < 0)
     {
       perror("execv error ");
       exit(1);
     }
   }
   
   
   if( fork() == 0 )
   {
     // in clhild 
     printf("3------------execlp------------n");
     if( execlp( "ls", "ls", "-a", NULL ) < 0 )
     {
       perror( "execlp error " );
       exit(1);
     }
   }
   
   
   if( fork() == 0 )
   {
     printf("4------------execvp------------n");
     if( execvp( "ls", arg ) < 0 )
     {
       perror( "execvp error " );
       exit( 1 );
     }
   }
   
   
   if( fork() == 0 )
   {
     printf("5------------execle------------n");
     if( execle("/bin/ls", "ls", "-a", NULL, NULL) == -1 )
     {
       perror("execle error ");
       exit(1);
     }
   }
   
   
   if( fork() == 0 )
   {
     printf("6------------execve-----------n");
     if( execve( "/bin/ls", arg, NULL ) == 0)
     {
       perror("execve error ");
       exit(1);
     }
   }
   return 0;
 }

 结果如下:

 

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

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

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