当前位置: 首页 > news >正文

【Linux进阶之路】进程(上)

文章目录

  • 前言
  • 一、操作系统加载过程
  • 二、进程
    • 1.基本概念
    • 2.基本信息
      • ①运行并观察进程
      • ②创建子进程
      • ③僵尸与孤儿进程(父子进程衍生出来的问题)
        • 1. 僵尸进程(Zombie状态)
        • 2. 孤儿进程
    • 3.基本状态
      • ①操作系统的状态(统一)
        • 1.运行态
        • 2.阻塞态
        • 3.挂起态
      • ②Linux系统的状态(实际)
        • 1.R状态
        • 2.S状态
        • 3.D状态
        • 4.T状态
        • 5.t状态
    • 4.优先级
      • ①查看优先级
      • ②修改优先级
        • 1.top
        • 2.nice
        • 3.renice
      • ③基本结构
    • 5.环境变量
      • ①简单认识
        • 1.PATH
        • 2.HOME
        • 3.SHELL
      • ②常用的环境变量
      • ③创建环境变量
      • ④进程内使用环境变量
        • 1.getenv
        • 2.命令行参数
        • 3.环境变量参数
  • 总结

前言

 回顾上文,操作系统是通过先描述再组织,进而管理软硬件资源的一款软件。那先组织再描述再组织的是什么呢?就是我们今天要讲的进程!

一、操作系统加载过程

 操作系统是一款软件,那么它是如何加载到内存呢?其实,计算机在开机时早已做好准备,在你按下开机键的那一刻,BIOS(基本输入输出系统,英文: Basic Input Output System)芯片就开始启动,开始做准备工作,通电唤醒CPU,IO接口,内存等资源,有了CPU这一名大将,便可以接着加载硬件资源,比如:网卡,显卡,磁盘等。接着再找到操作系统的引导文件,借助引导文件,将操作系统从磁盘加载到内存中,接着操作系统就开始一顿乱杀。

  • BIOS,是计算机的一个在CPU运行的可执行程序,说白了就是一个引子,加载基本资源,然后把操作系统带到内存当中,并让其管理软硬件资源的功能。

二、进程

1.基本概念

 再来想一个问题,那我们的qq是如何运行的呢?学到现在我们应该都知道可执行程序,也就是一个可以执行的文件,一般都在磁盘当中,那点击它之后,便在计算机系统中运行了起来,这之间需经过什么过程么?

 可执行程序的数据在磁盘当中,要想运行,首先需要加载到内存当中,因为磁盘的运行速度很慢只有1ms左右,而内存的运行速度在100ns左右,能更好的适配CPU中寄存器10ns左右的速度, 然后操作系统该如何管理加载到内存的数据呢?不可能直接管理一大堆数据吧?那么多的程序要运行,数据该多大?这样操作系统不得累死,为了操作系统管理方便,于是便将需要进行管理的属性信息组织到一块,统一进行管理,那操作系统管理的属性信息就叫做PCB(process control block),在Linux下叫做task_struct。以下我们统称为task_struct。

这是task_struct的源码:供参考。

struct task_struct {
volatile long state;  //说明了该进程是否可以执行,还是可中断等信息
unsigned long flags;  //Flage 是进程号,在调用fork()时给出
intsigpending;   //进程上是否有待处理的信号
mm_segment_taddr_limit; //进程地址空间,区分内核进程与普通进程在内存存放的位置不同//0-0xBFFFFFFF foruser-thead//0-0xFFFFFFFF forkernel-thread
//调度标志,表示该进程是否需要重新调度,若非0,则当从内核态返回到用户态,会发生调度
volatilelong need_resched;
int lock_depth;  //锁深度
longnice;       //进程的基本时间片
//进程的调度策略,有三种,实时进程:SCHED_FIFO,SCHED_RR,分时进程:SCHED_OTHER
unsigned long policy;
struct mm_struct *mm; //进程内存管理信息
int processor;
//若进程不在任何CPU上运行, cpus_runnable 的值是0,否则是1这个值在运行队列被锁时更新
unsigned long cpus_runnable, cpus_allowed;
struct list_head run_list; //指向运行队列的指针
unsigned longsleep_time;  //进程的睡眠时间
//用于将系统中所有的进程连成一个双向循环链表,其根是init_task
struct task_struct *next_task, *prev_task;
struct mm_struct *active_mm;
struct list_headlocal_pages;       //指向本地页面      
unsigned int allocation_order, nr_local_pages;
struct linux_binfmt *binfmt;  //进程所运行的可执行文件的格式
int exit_code, exit_signal;
intpdeath_signal;    //父进程终止是向子进程发送的信号
unsigned longpersonality;
//Linux可以运行由其他UNIX操作系统生成的符合iBCS2标准的程序
intdid_exec:1; 
pid_tpid;    //进程标识符,用来代表一个进程
pid_tpgrp;   //进程组标识,表示进程所属的进程组
pid_t tty_old_pgrp;  //进程控制终端所在的组标识
pid_tsession;  //进程的会话标识
pid_t tgid;
intleader;     //表示进程是否为会话主管
struct task_struct*p_opptr,*p_pptr,*p_cptr,*p_ysptr,*p_osptr;
struct list_head thread_group;  //线程链表
struct task_struct*pidhash_next; //用于将进程链入HASH表
struct task_struct**pidhash_pprev;
wait_queue_head_t wait_chldexit;  //供wait4()使用
struct completion*vfork_done;  //供vfork()使用
unsigned long rt_priority; //实时优先级,用它计算实时进程调度时的weight值//it_real_value,it_real_incr用于REAL定时器,单位为jiffies,系统根据it_real_value
//设置定时器的第一个终止时间.在定时器到期时,向进程发送SIGALRM信号,同时根据
//it_real_incr重置终止时间,it_prof_value,it_prof_incr用于Profile定时器,单位为jiffies。
//当进程运行时,不管在何种状态下,每个tick都使it_prof_value值减一,当减到0时,向进程发送
//信号SIGPROF,并根据it_prof_incr重置时间.
//it_virt_value,it_virt_value用于Virtual定时器,单位为jiffies。当进程运行时,不管在何种
//状态下,每个tick都使it_virt_value值减一当减到0时,向进程发送信号SIGVTALRM,根据
//it_virt_incr重置初值。
unsigned long it_real_value, it_prof_value, it_virt_value;
unsigned long it_real_incr, it_prof_incr, it_virt_value;
struct timer_listreal_timer;   //指向实时定时器的指针
struct tmstimes;     //记录进程消耗的时间
unsigned longstart_time;  //进程创建的时间
//记录进程在每个CPU上所消耗的用户态时间和核心态时间
longper_cpu_utime[NR_CPUS],per_cpu_stime[NR_CPUS]; 
//内存缺页和交换信息:
//min_flt, maj_flt累计进程的次缺页数(Copyon Write页和匿名页)和主缺页数(从映射文件或交换
//设备读入的页面数);nswap记录进程累计换出的页面数,即写到交换设备上的页面数。
//cmin_flt, cmaj_flt,cnswap记录本进程为祖先的所有子孙进程的累计次缺页数,主缺页数和换出页面数。
//在父进程回收终止的子进程时,父进程会将子进程的这些信息累计到自己结构的这些域中
unsignedlong min_flt, maj_flt, nswap, cmin_flt, cmaj_flt, cnswap;
int swappable:1; //表示进程的虚拟地址空间是否允许换出
//进程认证信息
//uid,gid为运行该进程的用户的用户标识符和组标识符,通常是进程创建者的uid,gid
//euid,egid为有效uid,gid
//fsuid,fsgid为文件系统uid,gid,这两个ID号通常与有效uid,gid相等,在检查对于文件
//系统的访问权限时使用他们。
//suid,sgid为备份uid,gid
uid_t uid,euid,suid,fsuid;
gid_t gid,egid,sgid,fsgid;
int ngroups; //记录进程在多少个用户组中
gid_t groups[NGROUPS]; //记录进程所在的组
//进程的权能,分别是有效位集合,继承位集合,允许位集合
kernel_cap_tcap_effective, cap_inheritable, cap_permitted;
int keep_capabilities:1;
struct user_struct *user;
struct rlimit rlim[RLIM_NLIMITS];  //与进程相关的资源限制信息
unsigned shortused_math;   //是否使用FPU
charcomm[16];   //进程正在运行的可执行文件名//文件系统信息
int link_count, total_link_count;
//NULL if no tty进程所在的控制终端,如果不需要控制终端,则该指针为空
struct tty_struct*tty;
unsigned int locks;
//进程间通信信息
struct sem_undo*semundo;  //进程在信号灯上的所有undo操作
struct sem_queue *semsleeping; //当进程因为信号灯操作而挂起时,他在该队列中记录等待的操作
//进程的CPU状态,切换时,要保存到停止进程的task_struct中
structthread_struct thread;//文件系统信息
struct fs_struct *fs;//打开文件信息
struct files_struct *files;//信号处理函数
spinlock_t sigmask_lock;
struct signal_struct *sig; //信号处理函数
sigset_t blocked;  //进程当前要阻塞的信号,每个信号对应一位
struct sigpendingpending;  //进程上是否有待处理的信号
unsigned long sas_ss_sp;
size_t sas_ss_size;
int (*notifier)(void *priv);
void *notifier_data;
sigset_t *notifier_mask;
u32 parent_exec_id;
u32 self_exec_id;spinlock_t alloc_lock;
void *journal_info;
};

像这样一个进程信息,操作系统并不会进行直接管理,而是将这样的进程放到指定的内存区域,然后自己弄个结构体指针,通过指针找到对应的进程即可。

那如果有很多的进程呢?我们可以从task_struct的源码中寻找答案:

//用于将系统中所有的进程连成一个双向循环链表,其根是init_task
struct task_struct *next_task, *prev_task;

图解:
在这里插入图片描述

  • 说明:这里的头尾相连省去了。

因此:操作系统的管理成本其实很低,只需要一个指针的大小,便可以管理所有存在内存中的task_struct。

那数据呢?有了task_struct你的信息和数据便也得到了管理,因为你的task_struct也会指向数据,方便对数据做更改和写入。

  • 因此:进程 等于 task_struct数据结构对象 + 代码和数据。

2.基本信息

①运行并观察进程

在vim上编辑如下代码:
在这里插入图片描述
然后运行此代码:

在这里插入图片描述

此时再开一个窗口会话,查看此进程的信息。

在这里插入图片描述
基本信息:
在这里插入图片描述

ps命令

ps ajx | less
  • 可以通过上下翻来查看进程
ps aux --sort -pcpu | less
//将cpu占用资源进行排序
ps aux --sort -pmem | less
//将内存占用资源进行排序
  • 查看进程的资源占用情况。

说明:一个进程只能有一个pid,一个可执行程序执行多次pid不同。

如何在进程里面查看pid与ppid呢?

介绍两个函数(系统调用接口):getpid() 与 getppid()

  • 举例代码
    在这里插入图片描述

  • 运行结果对比
    在这里插入图片描述
    可以看出是正确的pid与ppid

  • 看父进程到底是什么
    在这里插入图片描述

补充小知识点:kill -9 【进程id】 可以杀掉进程。

 那进程一般都存在哪呢?

在 Linux 下我们可以通过/proc(存的是内存级文件)目录中查看相关进程的信息,可以通过pid查看详细信息。

  • 运行刚才我们写的代码:
    在这里插入图片描述

  • 通过pid查看进程的相关信息:
    在这里插入图片描述

②创建子进程

  • 函数:fork
    在这里插入图片描述

  • 返回值
    在这里插入图片描述
    看返回值,可能会感到奇怪——为啥fork(创建成功)能返回两个不同返回值?子进程的代码和数据怎么办?

下面我们一个一个解释,首先父子进程的代码共享,画出图是这样的:

在这里插入图片描述

那为啥代码可以共享呢?因为代码不可以被修改!

其次我们再解释fork的原理,fork是一个函数。

其功能是完成子进程的task_struct创建,并对子进程的数据进行初始化,让子进程指向父进程的代码,在其返回时其实是父进程与子进程执行同一块代码,但其身份不同所以返回两个返回值,父进程接收子进程的pid是为了管理子进程。因为是父进程把子进程创建出来的!

那数据是能够被修改的,总不可能使用同一块数据吧?是这样的。我们猜测是将数据拷贝出来一份给子进程使用,但是这样可能会导致资源浪费严重,万一子进程只修改一个数据呢?全部拷贝损耗有点大了!

还记得我们之前讲过一种技术吗?——写时拷贝(C++拷贝构造)。

当只进行访问时,我们使用同一块数据,但当对数据进行修改时,我们对数据再进行拷贝,这样极大地提升了对内存资源的使用效率。

那我们画出的完整的图应该是这样的:

在这里插入图片描述

  • 再给出举例代码便于理解
    在这里插入图片描述

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

 再来谈谈bash命令行,我们执行的命令一般都是bash的子进程,那bash里面是如何创建子进程的呢?肯定绕不过系统调用接口——fork。

 总结一下:

  1. 父进程创建出子进程,并对子进程进行管理(fork对父进程返回子进程pid).
  2. 父子进程代码共享
  3. 数据当子进程进行只读时,共享,当子进程进行修改时会发生写时拷贝,从而进行修改拷贝之后的数据,因此数据可能共享,但共享部分的不同进程的访问权限不同!

③僵尸与孤儿进程(父子进程衍生出来的问题)

1. 僵尸进程(Zombie状态)

  • 运行此代码:
    在这里插入图片描述

  • 不断用ps命名查看任务信息
    在这里插入图片描述

  • 总结:形成此进程的原理很简单,子进程在运行结束时,应该交由父进程进行管理释放,但父进程由于在忙着自己的事情,因此父进程腾不出手将子进程进行释放。

  • 解决方法:此时我们是不能进行kill命令,杀掉此进程的,因为此进程是僵尸进程,算死过一次了,鞭尸并不管用,而应该杀掉父进程,这样子进程的资源就交由操作系统(init进程)进行管理释放。

2. 孤儿进程

  • 运行此代码:
    在这里插入图片描述

  • 运行结果
    在这里插入图片描述
    此时我们用kill命令对父进程发送9号命令。

  • 此时的运行结果:
    在这里插入图片描述
    可以看出子进程的父进程被干掉之后,变成了1号进程,那1号进程是谁呢?

  • 用ps命令进行查看在这里插入图片描述
    可见这个命令是操作系统的进程。

那为什么需要操作系统来管呢?它的爷爷进程管不了吗?这就需要考虑我们之前的原因是父进程把子进程创建出来的,那释放资源的信息是放在父进程中的,爷爷进程咋进行管理?是管不了的!因此释放资源的操作是由父进程进行管理,要么就是操作系统亲自进行管理。

那为啥这个进程叫孤儿进程呢?因为创建它的进程,被干掉了,就相当于世上唯一的亲人没了,只能被操作系统进行领养,成了孤儿,就叫做孤儿进程。

3.基本状态

①操作系统的状态(统一)

在网上我们可能会看到各种层出不穷的状态:

像这样的:
在这里插入图片描述
这样的:

在这里插入图片描述
这样的:
在这里插入图片描述

还有很多,这一般都是教材上统一描述计算机系统的一些图解,但真正上我们用的并不多,下面我们从几个常用的状态来理解操作系统的状态~

1.运行态

毫无疑问,就是把进程放在CPU上跑,可是CPU又不是只跑一个进程,而是多个进程,因此操作系统该如何进行管理呢?

图解:
在这里插入图片描述
其实,每一个运行的进程,被放在了一个运行对列中排队,当该一个进程跑时,我们就把此进程放在CPU中跑,等跑一段时间再将此进程放下来换另一个对列,这个在CPU跑的时间段,我们称之为时间片。

听过函数栈帧的想必都知道,在计算机中代码的运行在底层都转换为了汇编指令的执行,一般都是使用的寄存器来执行这些指令,那我们常见的寄存器有哪些呢?

ebp:栈底寄存器
esp:栈顶寄存器
功能:维护当前正在使用的函数空间
eax:通用寄存器,保留临时数据,常用于返回值,也用于赋值。
ebx:通用寄存器,保留临时数据——通常是用于初始化用户栈
eip: 指令寄存器,保存当前指令的下一条指令的地址,确保上一条指令能够继续运行下去。

这里我再强调一下,eip,也叫程序计数器,称为pc指针,其作用我举个具体场景进行分析。

#include <stdio.h>
int Add(int x, int y)
{int z = 0;z = x + y;return z;
}
int main()
{int a = 3;int b = 5;int ret = 0;ret = Add(a, b);printf("%d\n", ret);return 0;
}

调用函数的执行流:
在这里插入图片描述
可以看出,我们在调用函数时,跳转到了函数地址处所在的代码段,执行函数的代码,但执行完了,怎么返回呢?其实涉及到两个操作,第一个就是在call地址时,就把call指令的下一条指令进行了压栈操作,第二个就是在pop时,当执行ret返回命令时,会把压栈的地址再压入eip程序指针中,确保能执行到下一条指令。

到此我们提出来一个问题:当程序执行到一半,时间片到了,这该怎办呢?

是执行信息打包让进程带走,还是让CPU默默承受这一切?肯定是打包带走了,CPU才屁大一点地方,都给占用了,那进程还跑不跑了?

  • 因此:task_struct中必然有一处是记录程序运行的信息的,就是为了下次再次运行时,能够恢复运行信息。

说明:CPU是ns级别的,换算成s是10-9 次方,一般我们的进程放在CPU上运行10-6 次方秒,这已经足以让CPU做大量的工作,一般情况下,我们肉眼是观察不到计算机在轮流执行着进程,如果观察到了,那未免这个操作系统设计的也太挫了。

这里涉及到计算机的运行设置:

  • 并行:简单来说就是多个CPU跑多个程序
  • 并发:简单来说就是一个CPU跑多个程序

2.阻塞态

  • 当你的程序需要硬件设备资源时,这时会陷入阻塞状态。

一张图带你理解操作系统如何管理硬件资源:

在这里插入图片描述

  • 这时我们应该就差不多清楚,当计算机程序陷入等待计算机资源时,这时进程就为阻塞状态。

3.挂起态

 这个状态主要是为了解决阻塞态,会导致浪费内存资源的问题, 因为在阻塞状态中,可能后面还会有一大堆的等待进程, 进程的代码和数据并没有多大的用处,甚至还会浪费系统资源,因此为了提高内存的使用效率,可以将还没排上队的进程的代码和数据先放在磁盘中,等到这个进程了,再从磁盘中读取出来,接着进行使用。

  • 因此操作系统的真实状态应该是:阻塞+挂起
    在这里插入图片描述

②Linux系统的状态(实际)

在前面,我们其实已经说明了两种状态:僵尸状态和孤儿状态。

1.R状态

示例代码:
在这里插入图片描述

运行查看进程:

在这里插入图片描述

2.S状态

  • 示例代码:
    在这里插入图片描述

  • 用ps命令查看进程信息
    在这里插入图片描述

3.D状态

  • 说明:无法提供场景进行实验,我们这里就详细解释一下。
  1. D状态是一种比较深层次的睡眠状态,什么算比较深呢?也就是说操作系统都无法唤醒你,我们之前讲的S状态算是一种浅度睡眠,操作系统能进行杀死操作,而D状态操作系统是无法进行杀进程的,也就是说你给它发送kill -9 命令是不管用的!

  2. 为啥要这样做呢?因为当你在进行大量的磁盘写入状态时,你的进程是处于睡眠状态的,如果是浅度睡眠,也就是S状态,万一哪一天,系统资源不够,操作系统看你不顺眼,直接把你这个进程干掉了,你说你找谁说理去,操作系统只是在执行其应有的职责而已,这时为了解决这种问题,就有了D状态这一概念,在我写入磁盘文件不许操作系统的打扰,直到我写完了再说。

4.T状态

补充kill命令的几条信号:
在这里插入图片描述

9号:杀死进程。18号:继续进程。19号:停止进程。

举例代码:
在这里插入图片描述

观察流程:

在这里插入图片描述

  • 有同学就问了,这个状态有什么用呢?
     其实实验已经告诉我们了,在你想要单独查看进程时你可以将其它进程停止,这样之间的关系(比如父子关系)没有打破,还能更好的查看你想要查看的进程。

5.t状态

  • 全名:trace stop(追踪停止状态)

  • 举例代码:
    在这里插入图片描述

  • 观察流程:
    在这里插入图片描述

说明:还有一个X状态(dead状态),一般是无法看到的,因为经过上面的实验可以得出,进程结束之后会变成僵尸状态,等待父进程进行资源回收。

4.优先级

①查看优先级

在命令行输入:

ps len | grep 【进程】

可查看到进程的优先级
在这里插入图片描述

pri:优先级

也可以通过top命令查看进程:

在这里插入图片描述

②修改优先级

  • 说明:pri(new)= pri(old) + nice

注意:nice值是可以修改的但是区间在[-20,19],pid(old)一经设置便不可以被直接修改。
原因:调度器为了公平分配资源,禁止随意大量高频次的修改pri,这样在一定程度上会导致进程的饥饿问题(也就是有的进程可能分配到不足的CPU的资源),进而严重上会导致程序瘫痪。

  • pri修改优先级需要比较高的权限,因此普通用户只能nice往大了调,使优先级降低,root用户可以往大了也可以往小了进行调,不过范围还是再[-20,19]。

1.top

流程图:
在这里插入图片描述

2.nice

命令:

  • 在运行开始前设置nice值
nice -n 【nice值】 【进程】

图解:

在这里插入图片描述

3.renice

命令:

  • 在运行开始后设置renice
renice -n 【nice值】 【进程pid】

图解:
在这里插入图片描述

③基本结构

在这里插入图片描述

5.环境变量

  • 环境变量是在加载过程中,系统自动配置的变量,具有全局属性。

①简单认识

1.PATH

  • bash命令的默认查找路径。

在这里插入图片描述

  • 原因其实很简单,bash命令行的默认查找路径下没有当前路径。

如果要解决的话有两种办法,其一就是把可执行程序移到/user/bin路径下。
其二就是在默认路径上再加上我们的当前路径即可。

我们使用第二种方法:

在这里插入图片描述

  • 可以证明:bash是从PATH命令行中查找的命令。

  • 那如果我们一不小心将PATH覆盖呢?
     不用担心,因为PATH是内存级的变量,在启动xshell时,系统会默认将环境变量加载到内存中,如果你覆盖了,只需重启xshell即可

2.HOME

在这里插入图片描述

  • 可见打印出来的是家目录

3.SHELL

在这里插入图片描述

  • 查看当前我们使用的shell命令行

②常用的环境变量

  • env —— 查看所有的环境变量
    在这里插入图片描述

③创建环境变量

  • 命令
	export 【变量=初始值】将变量设置为环境变量。
  • 实验流程:
    在这里插入图片描述

  • 结果:我们最开始设置的变量并不是环境变量,而是本地变量,之后我们用export将本地变量导出才有了环境变量。

④进程内使用环境变量

1.getenv

  • 参数:环境变量——char* 类型

  • 返回值: char*
    在这里插入图片描述
    普通用户:
    在这里插入图片描述
    root用户:

    在这里插入图片描述

  • 因此:便可以根据环境变量识别不同的用户名,从而设置不同的权限。

2.命令行参数

这是main函数的前两个参数:

int main(int argv, char* argv[])
{return 0;
}
  • 顾名思义:就是打印出执行进程的命令

示例代码:
在这里插入图片描述

运行结果:

在这里插入图片描述

  • 由此推出:argv是对传入的参数用空格进行分割,得到的字符串的个数。argc存放的就是分割过后的字符串。
  • 引申出:可执行程序可以根据不同的选项从而实现不同的功能,这也是命令行的实现原理。

再来谈一下第二个参数的内存布局:

在这里插入图片描述
因此我们还可以这样进行使用:

int main(int argv, char* argv[])
{int i = 0;for(i = 0; argv[i]; i++){printf("%s\n",argv[i]);}return 0;
}

3.环境变量参数

除了命令行参数,还存在着一个环境变量参数:

int main(int argv, char* argv[], char* env[])
{return 0;
}

示例代码:
在这里插入图片描述

命令行流程图:
在这里插入图片描述

  • 总结:环境变量是能够被直接从父进程中继承下来的,并在创建子进程时放在进程中的environ中。
  • 补充:本地变量是不能够被继承的,因此在子进程中是无法看到的。

但是我们可能会对此命令产生疑问:

在这里插入图片描述

  • 其原因在于执行此命令时,bash并没有创建子进程,而是bash内部直接进行处理了,因此是可以打印出此本地变量的。这也被称之为内建命令

这里再补充两点:

  1. 取消环境或者本地变量
unset 【变量】
  1. 打印本地变量与环境变量
set

总结

 今天的分享就到这里了,如果觉得文章不错,点个赞鼓励一下吧!我们下篇文章再见

相关文章:

【Linux进阶之路】进程(上)

文章目录 前言一、操作系统加载过程二、进程1.基本概念2.基本信息①运行并观察进程②创建子进程③僵尸与孤儿进程&#xff08;父子进程衍生出来的问题&#xff09;1. 僵尸进程&#xff08;Zombie状态&#xff09;2. 孤儿进程 3.基本状态①操作系统的状态&#xff08;统一&#…...

爬虫018_urllib库_cookie反爬_post请求百度翻译获取百分翻译内容_以及详细翻译内容---python工作笔记037

然后我们来看如何用urllib发送post请求,这里我们 用百度翻译为例 我们翻译一个spider,然后我们看请求,可以看到有很多 找到sug这个 可以看到这里的form data,就是post请求体中的内容 然后我们点击preview其实就是 返回的实际内容 然后请求方式用的post 然后我们把上面的信息…...

【Nginx】Nginx网站服务

国外主流还是使用apache&#xff1b;国内现在主流是nginx&#xff08;并发能力强&#xff0c;相对稳定&#xff09; nginx&#xff1a;高新能、轻量级的web服务软件 特点&#xff1a; 1.稳定性高&#xff08;没apache稳&#xff09;&#xff1b; 2.系统资源消耗比较低&#xf…...

go语言从0基础到安全项目开发实战

一.环境搭建并helloworld 搭建环境比较简单 1.1安装SDK 到以下链接下 Go下载 - Go语言中文网 - Golang中文社区 下载windows版本64位zip包 https://studygolang.com/dl/golang/go1.20.7.windows-amd64.zip 1.2配置环境变量 不配置的话就只能在bin目录下才能运行go命令 …...

Kubernetes Service 工作原理

本文介绍了 Kubernetes Service 的概念、原理和具体使用。 作者&#xff1a;沈亚军 爱可生研发团队成员&#xff0c;负责公司 DMP 产品的后端开发&#xff0c;爱好太广&#xff0c;三天三夜都说不完&#xff0c;低调低调… 本文来源&#xff1a;原创投稿 爱可生开源社区出品&am…...

面部表情识别4:C++实现表情识别(含源码,可实时检测)

面部表情识别4&#xff1a;C实现表情识别(含源码&#xff0c;可实时检测) 目录 面部表情识别4&#xff1a;C实现表情识别(含源码&#xff0c;可实时检测) 1.面部表情识别方法 2.人脸检测方法 3.面部表情识别模型(Python) &#xff08;1&#xff09; 面部表情识别模型的训练…...

提升Element UI分页查询用户体验与交互:实现修改未保存提示

我实现的功能是在 element ui 的分页组件中进行分页查询时&#xff0c;如果当前有未保存的修改数据就提示用户&#xff0c;用户可以选择是否放弃未保存的数据。确认放弃就重新查询数据&#xff1b;选择不放弃&#xff0c;不重新查询&#xff0c;并且显示条数选择框保持原样&…...

UML-时序图

目录 时序图 时序图构成: 对象: 消息: 生命线(激活): 活动条: 时序图举例: 时序图 时序图也叫顺序图、序列图. 时序图描述按照时间的先后顺序对象之间的动作过程&#xff0c;是由生命线和消息组成 时序图构成: 对象: 对象是类的实例&#xff0c;对象是通过类来创建的&…...

Seata - 入门笔记

1、事务 访问并可能更新数据库中数据库中各种数据线的一个程序执行单元 原子性&#xff1a;事务是一个不可分割的工作单位&#xff0c;一个事务要么都做要么都不做 一致性&#xff1a;必须是使数据库从一个一致性到另一个一致性的状态&#xff0c;中间状态不能被观察到 隔离…...

springboot使用aop排除某些方法,更新从另外一张表,从另外一张表批量插入

AOP 在Spring Boot中使用AOP时&#xff0c;如果想要排除某些方法不被切面所影响&#xff0c;可以通过使用切面表达式中的!within关键字来实现。以下是一个示例&#xff1a; Aspect Component public class MyAspect {Before("execution(* com.example.service.*.*(..)) …...

Go 语言面试题(二):实现原理

文章目录 Q1 init() 函数是什么时候执行的&#xff1f;Q2 Go 语言的局部变量分配在栈上还是堆上&#xff1f;Q3 2 个 interface 可以比较吗&#xff1f;Q4 两个 nil 可能不相等吗&#xff1f;Q5 简述 Go 语言GC(垃圾回收)的工作原理Q6 函数返回局部变量的指针是否安全&#xff…...

SAP MM学习笔记16-在库品目评价

在库品目评价是指评估物料。具体比如物料价格&#xff0c;数量&#xff0c;保管场所等发生变化的时候&#xff0c;判断是否发生了变化&#xff0c;要不要生成 FI票&#xff0c;用哪个FI科目来进行管理等内容就叫在库品目评价。 在库品目评价有很多层级&#xff0c;这里先讲3兄弟…...

Azure通过自动化账户实现对资源变更

Azure通过自动化账户实现对资源变更 创建一个自动化账户第一种方式 添加凭据&#xff08;有更改资源权限的账户&#xff0c;没有auth认证情况&#xff09;创建一个Runbook&#xff0c;测试修改 AnalysisServices 定价层设置定时任务&#xff1a;开始定时任务&#xff1a; 第二种…...

使用luarocks安装cjson并使用cjson

1.luarocks安装 wget https://luarocks.org/releases/luarocks-3.3.1.tar.gz --no-check-certificatels -lrthtar -xvf luarocks-3.3.1.tar.gz mv luarocks-3.3.1 /usr/local/cd /usr/local/luarocks-3.3.1/./configure --prefix/usr/local/luarocks-3.3.1 vim /etc/profilePAT…...

【已解决】mac端 sourceTree 解决remote: HTTP Basic: Access denied报错

又是在一次使用sourcetree拉取或者提交代码时候&#xff0c;遇到了sourcetree报错&#xff1b; 排查了一会&#xff0c;比如查看了SSH keys是否有问题、是否与sourcetree账户状态有问题等等&#xff0c;最终才发现并解决问题 原因&#xff1a; 因为之前公司要求企业gitlab中…...

javaee dom4j读取xml文件

引入jar包 dom4j-1.6.1.jar 创建xml文件 <?xml version"1.0" encoding"UTF-8"?> <books><book id"1"><title ID"t1">背影</title><price>88</price><author>三毛</author>…...

各类背包问题

1、0-1背包问题 &#xff08;1&#xff09;用二维数组动态规划 #include<bits/stdc.h> using namespace std; int m,n; int w[50],c[50]; int dp[210][210]; int main() {cin>>m>>n;for(int i1;i<n;i){cin>>w[i]>>c[i];}for(int i1;i<n;…...

《练习100》91~95

题目91 # 自动生成字符串 # a [小马,小羊,小鹿] # b [草地上,电影院,家里] # c [看电影,听音乐,吃晚饭] # 随机生成三个0~2的数字&#xff0c;若是1&#xff0c;0&#xff0c;2 &#xff0c;则输出&#xff1a; 小羊在草地上吃晚饭 import random a [小马,小羊,小鹿] b […...

3.6 Spring MVC文件上传

1. 文件上传到本地 实现方式 Spring MVC使用commons-fileupload实现文件上传&#xff0c;注意事项如下&#xff1a; l HTTP请求方法是POST。 l HTTP请求头的Content-Type是multipart/form-data。 SpringMVC配置 配置commons-fileupload插件的文件上传解析器CommonsMultip…...

# X11、Xlib、XFree86、Xorg、GTK、Qt、Gnome和KDE之间的关系

X11、Xlib、XFree86、Xorg、GTK、Qt、Gnome和KDE之间的关系 很多人对于他们是啥是傻傻分不清的&#xff0c;我做了个表格供大家参考。 摘抄&#xff1a; X11是X Window System Protocol, Version 11&#xff08;RFC1013&#xff09;&#xff0c;是X server和X client之间的通…...

XML Group端口详解

在XML数据映射过程中&#xff0c;经常需要对数据进行分组聚合操作。例如&#xff0c;当处理包含多个物料明细的XML文件时&#xff0c;可能需要将相同物料号的明细归为一组&#xff0c;或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码&#xff0c;增加了开…...

Vue记事本应用实现教程

文章目录 1. 项目介绍2. 开发环境准备3. 设计应用界面4. 创建Vue实例和数据模型5. 实现记事本功能5.1 添加新记事项5.2 删除记事项5.3 清空所有记事 6. 添加样式7. 功能扩展&#xff1a;显示创建时间8. 功能扩展&#xff1a;记事项搜索9. 完整代码10. Vue知识点解析10.1 数据绑…...

IT供电系统绝缘监测及故障定位解决方案

随着新能源的快速发展&#xff0c;光伏电站、储能系统及充电设备已广泛应用于现代能源网络。在光伏领域&#xff0c;IT供电系统凭借其持续供电性好、安全性高等优势成为光伏首选&#xff0c;但在长期运行中&#xff0c;例如老化、潮湿、隐裂、机械损伤等问题会影响光伏板绝缘层…...

Mac下Android Studio扫描根目录卡死问题记录

环境信息 操作系统: macOS 15.5 (Apple M2芯片)Android Studio版本: Meerkat Feature Drop | 2024.3.2 Patch 1 (Build #AI-243.26053.27.2432.13536105, 2025年5月22日构建) 问题现象 在项目开发过程中&#xff0c;提示一个依赖外部头文件的cpp源文件需要同步&#xff0c;点…...

CSS设置元素的宽度根据其内容自动调整

width: fit-content 是 CSS 中的一个属性值&#xff0c;用于设置元素的宽度根据其内容自动调整&#xff0c;确保宽度刚好容纳内容而不会超出。 效果对比 默认情况&#xff08;width: auto&#xff09;&#xff1a; 块级元素&#xff08;如 <div>&#xff09;会占满父容器…...

Go 语言并发编程基础:无缓冲与有缓冲通道

在上一章节中&#xff0c;我们了解了 Channel 的基本用法。本章将重点分析 Go 中通道的两种类型 —— 无缓冲通道与有缓冲通道&#xff0c;它们在并发编程中各具特点和应用场景。 一、通道的基本分类 类型定义形式特点无缓冲通道make(chan T)发送和接收都必须准备好&#xff0…...

MySQL:分区的基本使用

目录 一、什么是分区二、有什么作用三、分类四、创建分区五、删除分区 一、什么是分区 MySQL 分区&#xff08;Partitioning&#xff09;是一种将单张表的数据逻辑上拆分成多个物理部分的技术。这些物理部分&#xff08;分区&#xff09;可以独立存储、管理和优化&#xff0c;…...

uniapp 小程序 学习(一)

利用Hbuilder 创建项目 运行到内置浏览器看效果 下载微信小程序 安装到Hbuilder 下载地址 &#xff1a;开发者工具默认安装 设置服务端口号 在Hbuilder中设置微信小程序 配置 找到运行设置&#xff0c;将微信开发者工具放入到Hbuilder中&#xff0c; 打开后出现 如下 bug 解…...

深度学习之模型压缩三驾马车:模型剪枝、模型量化、知识蒸馏

一、引言 在深度学习中&#xff0c;我们训练出的神经网络往往非常庞大&#xff08;比如像 ResNet、YOLOv8、Vision Transformer&#xff09;&#xff0c;虽然精度很高&#xff0c;但“太重”了&#xff0c;运行起来很慢&#xff0c;占用内存大&#xff0c;不适合部署到手机、摄…...

HybridVLA——让单一LLM同时具备扩散和自回归动作预测能力:训练时既扩散也回归,但推理时则扩散

前言 如上一篇文章《dexcap升级版之DexWild》中的前言部分所说&#xff0c;在叠衣服的过程中&#xff0c;我会带着团队对比各种模型、方法、策略&#xff0c;毕竟针对各个场景始终寻找更优的解决方案&#xff0c;是我个人和我司「七月在线」的职责之一 且个人认为&#xff0c…...