Linux---进程总结笔记

本文介绍了进程的基本概念,如进程与线程的区别,进程类型、状态和常用系统命令。还详细讲解了fork、exit、exec函数族,守护进程的创建,以及GDB调试多进程的过程。
摘要由CSDN通过智能技术生成

进程相关概念

进程是执行一个程序所分配的资源的总称,是动态的。

进程和线程的区别如图所示:
进程和线程区别
BSS段:存放程序中未初始化的全局变量
数据段:已初始化的全局变量
代码段:程序执行代码 //机器语言
堆(heap):malloc等函数分配内存
栈(stack):局部变量,函数参数,函数的返回值
进程控制块(pcb):进程用户,PID, 进程状态优先级,文件描述符表

  • 进程类型:交互进程(在shell下启动eg:./a.out)、批处理进程(和终端无关,顺序执行);守护进程(和终端无关。后台运行,在shell上无法控制,是分离的)。
  • 进程状态:运行态、等待态、停止态、死亡态(僵尸态):

常用查看系统进程的命令

  • ps 查看系统进程快照
  • top 查看进程动态信息
  • /proc 查看进程详细信息

应用举例:

/*  在终端下输入
参数:
-e:显示所有进程
-l:长格式显示更加详细的信息
-f 全部列出,通常和其他选项联用
*/
ps elf|grep filename
//查看某个进程
top -p PID  
  • jobs 查看后台进程
  • bg 将挂起的进程在后台运行
  • fg 把后台运行的进程放到前台运行
  • ctrl+z 把运行的前台进程转为后台并停止
  • ./test & 把test程序后台运行
  • nice [-n NI值] 按用户指定的优先级运行进程,NI数值越大优先级越低;
    (普通用户NI范围[0-19],root用户范围[-20~19];普通用户只能升高优先级不能降低。)
  • renice 改变正在运行进程的优先级,eg:renice [优先级] PID。

创建子进程

#include  <unistd.h>
 pid_t  fork(void);

fork函数应用举例:

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
 
int main()
{
    pid_t fpid;//fpid表示fork函数返回的值
    int count=0;
    fpid=fork();
    if(fpid<0)
        printf("error in fork!");
    else if(fpid==0)  //进程创建失败
    {
        printf("我是子进程,id:%d\n",getpid());
        count++;
    }
    else
    {
        printf("我是父进程,id:%d\n",getpid());
        count++;
    }
    printf("统计结果是:%d\n",count);
    exit(0);
}

执行结果:(注意:父子进程 执行顺序是不确定的,也有可能先打印子进程)
我是父进程,id:[父进程的PID] 
我是子进程,id:[子进程的PID]
统计结果是:1
统计结果是:1

上述结果表明:父子进程拥有独立的地址空间,互不影响,每个进程都只增加了自己内存空间中的count一次。

进程退出

#include <stdlib.h> 
void  exit(int  status);

exit函数会结束当前进程,关闭所有标准 I/O 流,释放动态分配的内存等。刷新(流)缓冲区,并将status返回(状态码0表示正常退出,非0值则表示出现了某种错误或异常情况)。

#include  <unistd.h>
void  _exit(int  status);

_exit函数它用于立即终止进程,不执行清理操作。

return 和exit的区别:普通函数return是返回上一级,而exit是直接退出程序。
(main函数结束时会隐式地调用exit函数)

进程回收

#include  <unistd.h>
pid_t wait(int *status);  // wait()函数返回子进程的PID,如果调用失败,则返回-1;

/*  wait()
1、用于父进程等待其子进程的状态变化,若子进程还没有终止,则父进程会被阻塞。
2、当父进程调用wait()检测到子进程终止时,释放子进程所占用的资源,包括内存、文件描述符等。
3、status用于存储子进程的终止状态,设置为NULL表示直接释放子进程PCB,不接收返回值
*/
#include  <unistd.h>
pid_t waitpid(pid_t pid, int *status, int option);

// waitpid() 函数是一个用于等待特定子进程状态改变的系统调用。它比 wait() 函数更加灵活,可以指定要等待的子进程的PID,以及一些附加选项。

exec 函数族

进程调用exec函数族执行某个程序,当前内容被指定的程序替换。
当有父子进程时,实现让父子进程执行不同的程序
这位前辈讲的exec 函数族非常详细,我这里就不赘述了。
给出两个简单的代码例子供大家理解,看注释

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main() {
    printf("Executing ls command using execvp()\n");
    char *args[] = {"ls", "-l", NULL};
    // 执行 ls 命令
    execvp("ls", args);
    // execvp() 函数只在出错时返回,因此如果执行到这里,说明调用失败
    perror("execvp");
    exit(EXIT_FAILURE);
    // 这里的代码不会被执行
    printf("This line will not be executed.\n");
    return 0;
}

这是个使用fork()函数创建父子进程,调用execl()的例子。

#include <stdio.h>
#include <unistd.h>

int main(){
   pid_t pid;
   printf("before exec\n");
   pid = fork();
   if(pid==0){
   	if(execl("/bin/ls","-a","-l","./",NULL)<0){
		perror("execl");
   	}
   }
   	printf("after execl\n");
}

执行结果为:
before exec
after execl
进程信息......
进程信息......

守护进程

守护进程(Daemon Process)是Linux三种进程类型之一,是 Linux 中的后台服务进程独立于控制终端,是一个孤儿进程。
目的:之所以脱离于终端是为了避免进程被任何终端所产生的信息所打断,其在执行过程中的信息也不在任何终端上显示。

更简便地创建守护进程:一般不推荐这样创建守护进程

// nohup 命令  
 nohup command [arguments] &    //& 符号表示将命令放入后台运行。

相关概念相关概念
守护进程创建过程:

  1. 创建子进程,父进程退出
  2. 子进程创建新会话
  3. 更改当前工作目录
  4. 重设文件权限掩码
  5. 关闭打开的文件描述符

实现代码展示如下

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/stat.h>
int main(){
 pid_t pid;
 pid = fork();
 if(pid<0){
   perror("fork");
   return 0;

 }else if(pid>0){  // 1、父进程退出  子进程变成孤儿进程,被init进程收养    子进程在后台运行
   exit(0);
//    sleep(100);
 }
 printf("I am a deamon\n");
 printf("sid=%d,pid=%d,pgid=%d\n",getsid(getpid()),getpid(),getpgid(getpid()));  

 if(setsid()<0){  // 2、子进程创建新会话  子进程成为新的会话组长  脱离原先的终端
   perror("setsid");
   exit(0);
 }  

 printf("after sid=%d,pid=%d,pgid=%d\n",getsid(getpid()),getpid(),getpgid(getpid()));

 chdir("/");  // 3、更改当前工作目录

 if(umask(0)<0){  // 4、重设文件权限掩码
   perror("unmask");
   exit(0);
 }
 
 close(0);   // 5、关闭打开的文件描述符
 close(1);
 close(2);
 printf("after close \n");  
 sleep(100);
}

执行结果
在这里插入图片描述

GDB调试多进程程序

  • set follow-fork-mode child 设置GDB调试子进程
  • set follow-fork-mode parent 设置GDB调试父进程
  • set detach-on-fork on/off 设置GDB跟踪调试单个进程或多个
    on: 只调试父进程或子进程的其中一个,(根据follow-fork-mode来决定),这是默认的模式
    off:父子进程都在gdb的控制之下,其中一个进程正常调试(根据follow-fork-mode来决定),另一个进程会被设置为暂停状态。
  • info inferiors 显示GDB调试的进程
  • inferiors 进程序号(1,2,3…) 切换GDB调试的进程
    这位前辈对于GDB调试部分写的非常详细。

以上是个人的一些学习总结和心得体会。参考了GPT及一些网络资源,后面还有学习心得会继续补充。新手,如有建议或写的不对的地方,欢迎讨论一下哦。欢迎交流,共同进步!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值