Linux进程相关知识

进程与程序区别

进程程序
状态程序运行动态体现静态的可执行文件
Windos下可执行文件类型是exeLinux下可执行文件类型是ELF,且无固定后缀
系统管理的最小单位进程调度的最小单位

`ELF`格式文件类型:可执行文件、可重定位文件、共享目标文件、核心转储文件

`readelf -h a.out`:查看可执行文件头部信息(文件创建之初就装有本身的相关属性,不仅仅只有可执行代码)

`task_struct`:对于进程来说比较重要的结构体,目前最大的结构体,包含所有进程信息

进程组织形式

init属于整个系统中最顶层的进程(没有父进程),其余进程都有父进程(若生父进程先被销毁,销毁时父进程的父进程会打印一句话,子进程会被系统派一个进程作为“养父”,二养父不具备打印这句话的功能),所以有的进程会显示有两个父进程;

pstree:查看系统进程树

ps -ef:查看系统当前进程

如下:

UID:所属用户

PID:类似于身份证(具有唯一性)

PPID:父进程的PID,可以相同是代表多个进程可以从属一个父进程

TTY:从属于哪一个控制台,若是?则是系统的守护进程

top -H:动态查看系统当前进程

htop:动态查看系统当前进程(需要自行安装插件)

//sudo apt-get install htop

进程的基础

要求:能用自己的话语表述完整流程

睡眠态、挂起态:缺失某些资源导致不可执行(前者是可响应信号后者可理解为深度睡眠)

暂停态:并没有到就绪队列中,而在等待命令(用户主动暂停)

僵尸态:进程被杀死,但是尸体还在,存在信息残留(什么原因被杀死、什么时候被杀死这些信息被封存在实体中)

死亡态:不存在任何信息残留

以下函数作了解部分,需要知道相关原理:

函数-fork
#include <unistd.h>
/*
功能:创建一个新进程
返回值:成功返回0或大于0的正整数 失败返回-1

特别注意:
1、成功 在子进程中返回0,父进程中返回子进程的PID(也就是一个大于0的正整数),所以返回值有两个
2、这就类似于“细胞分裂”,父子进程几乎一样,但父子进程的PID、记录锁、挂起的信号不同;并且位于两个不同的空间,相互独立(地址一样) 虚拟内存的地址相同,但是映射的物理地址不同
	对于一个变量,父子进程操作一个变量时,二者变量互不影响,虚拟地址相同,物理地址不同
	对于一个文件,父子进程读取一个文件时,若子进程后读取,会接着父进程读取位置继续读取
	这是由于对战数据会受到当前程序的影响,而文件的存在通常不受挡墙程序影响
3、子进程必定会从fork返回值的下一句逻辑语句执行,否则会产生无限子孙
4、父子进程的运行顺序是随机的,没有固定运行先后顺序
*/
pid_t fork(void);
案例
int main(int argc, char* arhv[])
{
    pid_t pid = fork();
    
    if(pid < 0)
    {
        perror("fork fail");
        return -1;
    }
    if(pid == 0)
    {
        printf("Son\n");
    }
    if(pid > 0)
    {
        printf("Father son_pid = %d\n", pid);
    }
    
    return 0;
}
函数-exec函数族
#include <unistd.h>
/*
功能:进程中加载新的程序文件
参数1:待加载文件路径(可以使用 whereis ls 来查看 ls 的路径)
参数2:待加载文件名字
grg:以列表的方式罗列参数
argv:以数组的方式罗列参数
返回值:成功不返回 失败返回-1

特别注意:
1、被加载文件的参数列表需要以自身名字为开始,以NULL结尾
2、执行成功后续的代码将不执行
*/
int execl(const char* path, const char* arg,...);
int execv(const char* path, char* const argv[]);
案例
int main(int argc, char* argv[])
{
    int ret = execl("/bin/ls", "ls", "l", NULL);
    //execlp("ls", "ls", "-l", NULL);
    
    /*
    char* argv[] = {"ls", "-l", NULL};
    execv("/bin/ls", arg);
    //execvp("ls", arg);
    */
    
    if(ret == -1)
    {
        //只有执行失败才会返回
        perror("execl error");
    }
    else	//一旦exec族函数被执行成功,后面的代码将不会执行
    {
        printf("execl ok!\n");
    }
    
    return 0;
}
函数-exit/_exit
#include <unistd.h>
#include <stdlib.h>
/*
功能:结束本进程
参数:子进程退出值(正常为0,异常非0)
返回值:不返回
*/
void _exit(int status);
void exit(int status);

案例

void fun1()
{
    printf("fun1\n");
}
void fun2()
{
    printf("fun2\n");
}

int main()
{
    //atexit函数用于注册函数,并不会真正执行被注册函数
    //当进程退出时,被注册函数才会退出
    //执行顺序符合栈规则,先注册fun1,后注册fun2,所以先结束进程fun2,后结束进程fun1
    atexit(fun1);
    atexit(fun2);
    
    //exit 可以清理缓冲区(输出缓冲区内容) 用于结束当前进程,区别于return
    //exit(0);
    
    //_exit 不会清理缓冲区
    _exit(0);
    
    //return 会清理缓冲区 用于结束当前函数,在哪个函数就结束哪个函数
    //return 0;
}
缓冲区清理五种情况:
    1、return
    2、exit
    3、"\n"
    4、缓冲区已满
    5、手动清理"fflush"
函数-wait/waitpid
#inlcude <sys/wait.h>
/*
功能:等待子进程
sata_loc:子进程退出状态
pid:
option:
返回值:失败返回-1
*/
pid_t wait(int* sata_loc);
pid_t waitpid(pid_t pid, int* stat_loc, int options);
案例
int main()
{
    pit_t pid = fork();
    if(pid < 0)
    {
        perror("fork error");
        return -1;
    }
    
    //子进程
    if(pid == 0)
    {
        printf("sub pid = %d, ppid = %d\n", getpid(), getppid());
        /*
        
        return 255;
        
        exit(88);
        
        */
    }
    
    //父进程
    if(pid > 0)
    {
        sleep(1);	//若不写这一句话,那么子进程后执行后退出,那么父进程先结束,子进程就变成孤儿进程 
        printf("sub pid = %d, ppid = %d\n", getpid(), getppid());	//getpid:获得当前进程pid
        
        int stat;
        pit_t ret = wait(&stat);//wait阻塞等待(会一直等到子进程结束,若子进程不结束,那么会影响父进程执行)waitpid非阻塞等待,若子进程未结束,也不影响父进程执行,并且获取不到子进程pid,返回0,告知子进程还未结束(相较于wait多一种情况)
        if(ret < 0)
        {
            perror("wait error");
        }
        else
        {
            printf("exit sub pid = %d,exit value = %d\n", ret, stat);
        }
    }
    
    return 0;
}

精灵进程

进程组

  1. 每运行一个程序就会有一个进程,进程组就是一组进程(便于多个关联进程的管理),拥有一个组ID(通常使用进程组中所有PID最小的);

  2. 组长进程若先退出不会有新进程组长,且会等到进程组全部成员退出,进程组才会消亡;

  3. 若进程成员创建子进程,同样子进程会和父进程在同一组;

  4. 进程必定属于某一个进程组,且只能属于一个进程组;

对话期
  1. Linux是多用户多任务操作系统;

  2. 用户登录一次系统就会形成一个会话,一个会话只有一个领导和一个前台进程组还可以有一个控制终端,可以拥有多个进程组(会话包含控制进程(会话首进程)、一个前台进程组、任意个后台进程)

终端
  1. Linux通常说的终端就是于用户交互的命令窗口

  2. 精灵进程又叫守护进程/后台进程,若要关闭后台进程则只能关闭系统,而前台进程可以受到多个影响,如关闭终端、Ctrl C、关闭终端;./a.out &这就是一个最基础的精灵进程

精灵进程(了解)

创建流程:

  1. 先创建一个进程p1,这个p1会变成进程组组长;

  2. 然后利用p1创建其子进程p2,然后需要干掉p1p2会成为会话期的组长;

  3. 然后利用p2创建其子进程p3,然后需要干掉p2

  4. 最后p3再去隐藏文件掩码等威胁自己存在的信息;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值