操作系统学习笔记(三) 进程

本文详细介绍了操作系统的进程环境,包括C程序存储空间布局、动态库与静态库的区别及使用。深入讲解了进程控制,如进程ID、进程组、进程创建(fork)以及写时拷贝机制。还探讨了守护进程的创建方法及其特点,并阐述了进程的终止方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、进程环境

  C程序存储空间布局:

      正文段:只读、存放CPU执行的机器指令,可共享

      数据段:也叫初始化数据段。包含程序中需要明确赋值的变量,如 int max =99;

      BSS段:也叫未初始化的数据段,在程序开始执行前,内核将此段中数据初始化为0或空指针,如long sum[100];

      栈:存放自动变量(即局部变量),以及每次函数调用时所需要保存的信息

      堆:通常在堆中实现动态存储分配,位于BSS和栈之间

     其中,如寄存器变量或全局变量存放在数据段或BSS段。图示如下:

二、动态库与静态库

     1.静态库:链接阶段直接被链接到二进制文件中,生成文件体积大,但不再依赖于库。

     2.动态库:运行阶段加载

     1)C文件生成动态库  gcc -shared a.c -o libdb.so

     2)调用方法:

          运行时调用:  如调用libxxx.so库中的func()函数,则:gcc b.c -o bapp -l xxx.so

           要求动态库加载路径默认在/lib和/usr/lib,或通过/etc/ld.so.conf配置或环境变量LD_LIBRART_PATH指定

          手动加载动态库:利用C库中的dlopen等接口

              打开库:  *p = dlopen("libxxx.so",RTLD_NOW);   //第二个参数可以更改

                            void (*func)(void) = dissym(p,"func");

                             func();

               编译:  gcc a.c -l xxx -o.app

三、进程控制

     1.进程ID为0是交换进程,为1是init进程,获取pid调用函数pid_t getpid(void);  获取父进程pid用pid_t getppid(void);头文件都是<sys/types.h> 和 <unistd.h>,pstree命令可以查看进程家族树。

     2.进程组:一次会话中的多个进程可以属于一个进程组(如管道的两个进程),进程组ID为PGID,会话ID为SID

          pid_t  getpgrp(void);   int setpgid(pid_t pid,pid_t pgid);

         对于一个已经执行exec的子进程,父进程不能调用setpgid来设置子进程的进程组ID

         调用setsid(void)可以创建会话,但调用它的进程不能是某个进程组的组长。防止该进程组其他成员无法会话迁移。

     3.进程的创建——fork()

     调用folk创建进程,调用进程为父进程,返回进程为子进程。返回两次,一次是父进程的返回值返回子进程的进程号,另一次是子进程的返回值,返回0。子进程是父进程的副本,拷贝了一份父进程的堆栈空间,父子进程只共享正文段。

        ret=fork();

     if(ret==0)   { //子进程代码段}

       else  if (ret>0)   {//父进程代码段}

        else  {  //fork 失败}

     注意:一般在fork进程中,父子进程并不同步,因此不一定是父进程还是子进程先进行。子进程不继承父进程的文件锁,子进程未处理信号集设置为空集。

     4.写时拷贝:子进程的页表项指向与父进程指向的物理内存页相同,当父子都只读时则公用一个物理内存页,但由一方尝试修改则会引发缺页异常,此时内核将为该页面创建一个新的物理页面并复制其内容,使得父子进程各自真正拥有自己的物理内存,然后将页表项标记位可写。

     5.FD_CLOSEXEC(fd)与O_CLOSEXEC(open)标志位在子进程调用exec时会响应关闭文件,防止父子进程由于共享文件偏移量时读写文件发生混乱。

     6.守护进程daemon

     特点:在后台运行不受任何终端控制,一直到系统退出(如SIGINT、SIGQUIT、SITSTP等终端信号并不能干扰它,关闭终端也不能将其杀死。守护进程退出的情况只有stop命令、发送信号杀死守护进程或守护进程代码bug)。

     创建方法:double_fork magic

     1)fork()函数,父进程退出子进程继续

     2)子进程摆脱环境控制:修改进程当前目录为根目录(chdir("/"))调用setsid切断与控制终端的关系并创建一个新的会话,设置文件模式创建掩码为0(umask(0))

     3)再次fork(),父进程退出子进程继续,使得daemon不是会话首进程

     4)关闭标准输入、标准输出、标准错误

也可以调用glibc库中的daemon函数一次创建:

#include <unistd.h>

int daemon(int nochdir,int noclose);   //一般参数为0,0

     7.进程的终止:正常——从main函数return、调用exit、调用_exit。异常——调用abort、接收到信号由信号终止

          exit与_exit区别是,exit退出且调用清理函数,关闭打开的方法、写入缓冲数据、删除临时文件然后再调用_exit

     8.等待子进程

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值