Linux C语言 学习之 进程(1)

组成

  1. 程序:

    1. 数据段:存放程序中已经初始化的全局变量的一块内存区域

    2. 代码段:存放程序执行代码的一块内存区域

    3. BSS段:存放程序中未初始化的全局变量的一块内存区域

  2. 堆:存放进程运行中被动态分配的内存段,malloc申请,free释放

  3. 栈:程序中临时创建的局部变量(不包括static定义),函数传入的参数、函数返回值

  4. 进程控制块:

    1. 进程控制块

    2. 进程标识 PID

    3. 进程用户

    4. 进程状态、优先级

    5. 文件描述符表 最多默认创建1024个,当前打开的文件

类型

  1. 交互进程:shell下启动,可前台 可后台运行

  2. 批处理进程:和终端无关,被提交到一个作业队列里以便顺序执行

  3. 守护进程:和终端无关,后台进程

状态

  • 运行、等待、停止、死亡(僵尸)

Shell 操作

查看进程信息:
  1. ps:查看进程快照 ps -elf ps -elf|grep + 进程名

  2. top:查看进程动态信息 翻页:shift+>/< top -p + PID

  3. /proc:查看运行进程详细信息 ls /proc

进程优先级:
  1. nice 按用户指定的优先级运行进程

  2. nice -n NI + 启动名称

  3. nice范围 -20 ~19 数值越大优先级越低

  4. 普通用户只能调制范围0-19 ,只能调高不能调低,而且只能调整自己的进程

  5. 只有root用户才可以设置进程NI值为负值,而且可以调整任意进程

  6. renice 改变进程优先级

  7. renice NI +PID

进程运行:
  1. jobs:查看后台进程

  2. bg:将挂起的进程在后台运行

  3. fg:把后台运行的进程放到前台运行

  4. ctrl+z 把前天进程转为后台并停止

  5. 运行进程 + & 把进程后台运行 ./test &

创建子进程

pid_t fork(void);

  • 创建失败返回 -1,创建成功父进程返回子进程进程号,子进程返回0

  • 通过pid值来区分父子进程

  • 子进程只执行fork之后的代码

  • 获取进程号:getpid();

  • 获取父进程号: getppid();

  • 子进程继承父进程内容

  • 父子进程有独立的地址空间,互不影响

  • 若父进程先结束,子进程变为孤儿进程,被init进程收养,子进程变为后台进程

  • 若子进程先结束,父进程没有及时回收,子进程则变为僵尸进程

  • 判断子进程,可通过创建的序号区分哪一个子进程

进程退出:

结束当前进程并返回状态值。

  • exit(); 刷新 流 的缓冲区

  • _exit(); 不刷新

  • main函数执行完,会隐式的调用exit函数,普通函数的return是返回上一级函数

进程回收:

避免僵尸进程

  • pid_t wait(int *status)

    • 子进程不退出,会一直堵塞父进程

  • WEXITSTATUS(status)、

    • 获取子进程返回值

  • WIFEXITED(status)

    • 判断子进程是否正常结束

  • pid_t waitpid(pid_t pid,int *status,int option)

    • pid = -1,等待回收任意子进程,这是功能和wait一样

    • pid > 0,等待回收指定pid子进程

    • option = 0 堵塞

    • option = WNOHANG 子进程状态不发生改变,则waitpid不堵塞

    • wait(status) = waitpid(-1,status,0);

exec函数族

  • 进程调用exec函数族执行某个程序

  • 进程当前内容被指定程序替换

  • 实现父子进程执行不同的程序

  • 父进程创建子进程

  • 子进程调用exec函数族

  • 父进程不受影响

  • execl/execlp

        程序路径/环境变量

  第0个参数必须填上,参数最后一个必须是NULL

  int execl(const char *path, const char *arg, ...);

  int execlp(const char *file, const char *arg, ...);

  int execv(const char *path, char *const argv[]);

  int execvp(const char *file, char *const argv[]);

  • path:可执行文件的路径名字

  • arg:可执行程序所带的参数,第一个参数为可执行文件名字,没有带路径且arg必须以NULL结束

  • file:如果参数file中包含/,则就将其视为路径名,否则就按 PATH环境变量,在它所指定的各目录中搜寻可执行文件。

  • exec族函数参数极难记忆和分辨,函数名中的字符会给我们一些帮助:

    • l : 使用参数列表

    • p:使用文件名,并从PATH环境进行寻找可执行文件

    • v:先构造一个指向各参数的指针数组,然后将该数组的地址作为这些函数参数。

    • e:多了envp[]数组,使用新的环境变量代替调用进程的环境变量

守护进程

  • 后台服务进程

  • 生存期较长的进程,通常独立于控制终端(为避免终端所产生的信息所打断)并且周期性的执行某种任务或者等待处理某些发生的事件

  • 进程组:进程集合,每个进程组都有一个组长,其进程ID就是该进程组ID

  • 会话:进程组集合,每个会话都有一个组长,其进程ID就是该会话组的ID

  • 控制终端:每个会话可以有一个单独的控制终端,与控制终端连接的leader就是控制进程

shell指令:nohup xxx &

  • 步骤:

       1. 创建子进程,父进程退出(子进程变成孤儿进程被init收养,子进程后台运行)

                pid = fork();

                if (pid > 0) {

                exit(0);}

        2. 创建新的会话 (子进程成为新的会话组长,子进程脱离原来的终端)

                if(setsid() < 0){

                exit(-1);}

                getpid();getsid();getpgid();

        3. 更改当前工作目录(守护进程一直后台运行,其工作目录不能被卸载)

                chdir("/")

                chdir("/tmp");

        4. 重设文件权限掩码(文件权限掩码设置为0,只影响当前进程)

                if(umask(0) < 0){

                exit(-1);}

        5. 关闭打开的文件描述符(关闭所有从父进程继承过来的打开文件,已脱离终端,stdin/stdout/stderr/)无法在使用

                for(int i = 0;i < 3;i++){

                close(i);}。

                fdtablesize = getdtablesize();

                for (fd = 0; fd < fdtablesize; fd++)

                close(fd);

  • 9
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

丶小破孩

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值