ICode9

精准搜索请尝试: 精确搜索
首页 > 系统相关> 文章详细

Unix高级编程 进程控制(1)

2022-01-18 09:03:18  阅读:140  来源: 互联网

标签:fork 调用 函数 编程 高级 Unix 描述符 进程 ID


 看到这里首先需要对进程有一个清晰的了解,才能继续,过些日子,我在写一篇有关进程的基础理解的文章。 这里认为大家对进程已经有了一个初步的认知。这些文章都是对unix高级编程这本书进行的总结,一方面是方便自己回顾,一方面是加深自己的理解,也可以向大家分享一下学习的经验。

   进程的控制,主要包含创建进程、执行程序、进程终止。

进程标识

 进程标志也可以说是进程的号,专业点叫进程ID。进程的标识符ID 是唯一的,也就是每一个进程及对应的ID 都具有唯一性。 进程ID 虽然具有唯一性,但进程ID 具备可重复性,当一个进程终止后,其进程ID 就是可以被复用的ID。

进程中有一些专用的进程,但具体细节随着实现的不同。

ID:0 系统的调度进程,也称交换进程。(swapper进程)。

ID: 1 init进程, 在自举过程结束时由内核调用。(自举是什么意思)

ID: 2 页守护进程(page daemon)。此进程负责支持虚拟储存系统的分页操作。

#include <unistd.h>

pid_t getpid(void); //调用进程的ID

pid_t getppid(void); // 调用进程的父进程ID

uid_t getuid(void);  //调用进程的实际用户ID

uid_t geteuid(void);  //调用进程的有效用户ID

gid_t getgid(void);   // 调用进程的实际组ID

gid_t getegid(void);  //调用进程的有效组ID

创建一个进程:

#include <unistd.h>

pid_t fork(void);

  由fork创建的进程被成为子进程,fork函数被调用一次,被返回两次。

其中:

父进程返回的子进程的进程ID。

子进程的返回的是0。

子进程和父进程继续执行fork调用之后的指令。 子进程是父进程的副本。 例如: 子进程获得父进程的数据空间、堆和栈的副本, 这是子进程所拥有的副本,父进程和子进程并不共享这些储存空间,父进程和子进程共享正文段。

 由于fork 之后,经常跟随着exec,所以出现了一个新的内容,写时复制。 意思就是,将这一段区域由子进程和父进程共享,内核将它们的访问权限设置为只读,只有当子进程或者父进程想要修改的时候,则内存只为修改那部分创建一份副本。通常为虚拟系统中的一个页。

另外还有一个问题,是fork 之后是父进程先执行,还是子进程先执行,是不确定的。 这与操作系统的内核有关系,如果想让某个进程先执行,我们需要以某种形式,进行进程之间的通信。

#include "apu.h"

int val = 6;
char buf[] = "a write to stdout";

int main(void)
{
    int var;
    pid_t pid;

    tempvalue = 88;

   if(pid = fork() <0){
   printf("fork error");
   } else if (pid == 0){
      val++;
      tempvalue++;
   }else{
     sleep(2);
   }

  printf("pid = %ld,val = %d, var = %d\n",(long)getpid(),val,tempvalue);
 
}

//

结果: 子进程: var = 7; tempvalue = 89;

           父进程: var =6.tempvalude =88

原因就是,子进程和父进程共享一份代码,但子进程拥有父进程fork 之前的数据副本。

文件共享

子进程和父进程之间的 文件共享

fork 具有另外一个特点,父进程所有打开的文件描述符,全部被复制到子进程。 这里说的复制是只文件描述符类似全部 执行乐dup 函数。(这里去看文件描述符部分)

dup (int fd);
// 复制一个现有的文件描述符,返回一个指向文件描述符的新值
//dup 函数返回的一定是当前文件描述符可以使用的最小值

复制的文件描述符,和原来的文件描述符,共同指向同一个文件表项。

有关文件表的内容,我将在linux 操作系统 的文件系统中进行详细解释。

需要强调的一点是,父进程和子进程 共享一个文件偏移量, 也就是fork 之后,子进程和父进程同时往一个文件内输出,容易照成输出混合, 所以父进程和子进程之间要进行同步处理。

fork 之后的文件描述符,有两种常见的状况:

(1) 父进程等待子进程完成。父进程在子进程终止前,不对文件描述符进行处理。

(2) 当进程终止之后,对任一文件描述符进行做相应的更新。父进程和子进程执行不同的代码段,关闭它们不需要使用的文件描述符。 这样就不会干扰对方使用文件描述符。

子进程继承 父进程的属性:

1. 实际用户ID、实际组ID、有效用户ID、有效组ID。

2. 附属组ID。

3. 进程组ID。

4.会话ID。

5. 当前工作目录根目录。

6. 环境、储存影像、资源限制。

父进程和子进程之间的区别是什么呢?

fork 的返回值不同,进程ID 不一样。

两个进程的父进程ID 不一样。

子进程不继承父进程设置的文件锁。

子进程未处理的闹钟被清零。

子进程设置的未处理信号集设置为空集。

fork 之后 对子进程有两中想法,

一是父进程和子进程执行不同的代码段。

二是 一个进程要执行另外的程序,在fork 之后,执行exec()。

函数 vfork

 vfork 的返回值和调用系列和fork 相同,但语义不同。

    vfork 函数的目的是用于创建一个线程,而且该线程的目的是执行exec一个新的程序。 所以它不会将父进程的地址空间完全复制到子进程中去,因为子进程会立刻调用exec 函数,所以在调用exec函数之前,子进程是在父进程的空间中运行。

   vfork 和fork 之间的一个区别是,能够保证子进程先运行,在子进程调用exec或exit后父进程才可能被调度运行。

#include "apue.h"

int globvar = 6
int main(void)
{
   int var;
   int pid;
    
   printf("before vfork\n");
   if((pid==vfork()==0)
   {
     globavr++;
     var++;
     _exit(0);
   } else if(pid>0){
     print("pid = %ld, glob = %d,var = %d\n",(long)getpid(),globvar,var)
   }
    exit(0);
}

运行结果是 glob = 7,var = 89。

子进程对变量进行增加,改变了父进程中变量的值,因为子进程在父进程中运行。

8、进程退出的方式

进程有5中正常终止和异常终止方式。

(1) 在main 函数中调用return 函数。

(2) 调用exit() 函数。这个函数有ISO C 定义。其会调用各种注册的终止函数。

(3)调用_exit() 或_Exit()函数,不需要调用终止函数。

(4) 进程中的最后一个线程,在其启动例程中执行return 语句。

(5) 进程中的最后一个线程调用pthread_exit函数。

3种异常终止的函数:

(1)调用abort 函数。

(2)当进程接受到某些信号。

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

    不管进程如何终止,最后都会执行内核中的同一段代码,这段代码为相应的进程关闭所有打开的应用,释放它所使用的储存器。 进程将退出状态作为参数传递给终止函数。

标签:fork,调用,函数,编程,高级,Unix,描述符,进程,ID
来源: https://blog.csdn.net/SYY_LR/article/details/122114500

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有