Linux_进程概念_冯诺依曼_进程概念_查看进程_获取进程pid_创建进程_进程状态_进程优先级_环境变量_获取环境变量三种方式_3

news2024/12/23 17:45:59

文章目录

  • 一、硬件-冯诺依曼体系结构
  • 二、软件-操作系统-进程概念
    • 0.操作系统做什么的
    • 1.什么叫做进程
    • 2.查看进程
    • 3.系统接口 获取进程pid- getpid
    • 4.系统接口 获取父进程pid - getppid
    • 5.系统接口 创建子进程 - fork
      • 1、手册
      • 2、返回值
      • 3、fork做了什么
      • 4、基本用法
    • 6.进程的状态
      • 1、进程的状态是什么
      • 2、进程的状态
    • 7.Linux下的进程状态
      • 1、运行状态 - R
      • 2、阻塞状态 - S (可中断)
      • 3、阻塞状态 - D (不可中断)
      • 4、僵尸状态- Z 和 死亡状态 - X
      • 5.停止状态 - T / t
    • 8.孤儿进程
    • 9.进程优先级
      • 1、什么是优先级 vs 权限 (是什么)
      • 2、为何会存在优先级?(为什么)
      • 3、Linux下的优先级的相关概念和操作(怎么办)
    • 10.竞争性_独立性_并行_并发_进程间切换
  • 三、环境变量
    • 1.环境变量操作
    • 2.让自己程序和命令一样执行
    • 3.常见环境命令
    • 4.环境变量的C、C++获取方式(代码如何获取环境变量)
      • 1、mian函数参数获取环境变量
      • 2、通过C语言提供的全局变量获取 - environ
      • 3、获取环境变量函数 - getenv(const char* name)


一、硬件-冯诺依曼体系结构

我们常见的计算机,如笔记本。我们不常见的计算机,如服务器,大部分都遵守冯诺依曼体系。
在这里插入图片描述
输入:键盘,话筒,摄像机,磁盘,网卡…
输出:显卡,音响,磁盘,网卡,显卡…
(运算器+控制器)[cpu]:算术计算+逻辑计算
储存器:就是内存

为什么要有内存,直接将输入设备和cpu直接连接不可以吗?
a. 技术角度
cpu的运算速度>寄存器的速度>L1~L3Cache>内存>>外设(磁盘)>>光盘磁带
数据角度:外设不和CPU直接交互,而是和内存交互,CPU也是如此。
内存在我们看来,就是体系结构的一个大的缓存,适配外设和CPU速度不均的问题的!
b. 成本角度
造价成本:寄存器>>内存>>磁盘(外设)

几乎所有的硬件,只能被动的完成某种可能,不能主动的完成某种功能,一般都是配合软件完成的(OS+CPU)

二、软件-操作系统-进程概念

0.操作系统做什么的

操作系统是一款软件,搞管理的软件,什么叫做管理, 如何理解?
管理的本质:不是对被管理对象进行直接管理,而是只要拿到被管理对象的所有的相关数据,我们对数据的管理,就可以体现对人的管理————对数据做管理

数据是有多少的区分的如何管理好大量数据?
大量数据,就需要结构化,也就是对数据结构的管理。

管理的核心理念:先描述,再组织

在这里插入图片描述

1.什么叫做进程

进程是一个运行起来的程序

操作系统里面可能同时存在大量的进程!操作系统需要对进程管理,对进程管理本质就是对进程数据的管理,就需要先描述,再组织

struct task_struct : 就是描述进程的,像这样描述进程的统称为进程控制块PCB( proccess ctrl block ),而task_struct就是其中一个具体实例。

进程 = 可执行程序 + 该进程对应的内核数据结构(PCB)

OS为什么给我们提供服务?
printf 向显示器打印,本质就是将数据写到硬件上,我们的c程序没有资格向硬件写入,计算机和os设计出来是为了给人提供服务的

如何提供服务?
操作系统不相信如何人!不会直接暴露自己的任何数据结构,代码逻辑,其他数据相关的细节!!操作系统是通过系统调用的方式,对外提供接口服务的,Linux操作系统是用c语言写的,这里所谓的“接口”,本质就是c函数!我们学习系统编程—本质就是在学习这里的系统接口

2.查看进程

先写一个死循环程序编译运行:

#include<stdio.h>
int main()
{
  while(1)
  {
    printf("I am a process!\n");
  }
  return 0;
}

查看进程方式1:
这是查看进程的第一种方式,也是最常用的。

ps ajx 进程名 | grep 进程名

在这里插入图片描述
有头部提示:

ps ajx |head -1 && grep 进程名称

在这里插入图片描述

为什么会有两个?
我们自己写的代码,编译称为可执行程序,启动之后就是一个进程!
别人写的,启动之后也是一个进程!比如:ls pwd touch grep …
那么这些程序,在系统中的位置— /usr/bin
第二个进程就是查询程序的进程,第一个就是我们编写的程序的进程。


当前路径?
根目录里有一个目录proc,放内存文件系统,系统里放着当前系统实时的进程信息。查看目录里面的内容:
在这里插入图片描述

上面的蓝色就是进程的pid!
每一个进程在系统中,都会存在一个唯一的标识符(pid->process id)!就如每人都有一个身份证号。

查看运行进程目录其中有一个cwd:
在这里插入图片描述
cwd :current work directory 进程当前工作路径

当前路径??
当前进程所在路径,进程自己会维护

查看进程的方式2:
先查进程pid在再/proc里的进程目录查看详细信息。

那么上面所说的pid,当前路径等待,是进程的内部属性,程序运行放在哪里?
进程的进程控制块-PCB(task_struct)结构体中

3.系统接口 获取进程pid- getpid

命令行查看系统接口getpid:

man 2 getpid

在这里插入图片描述

#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
int main()
{
  printf("我的pid是 %d\n",getpid());
  return 0;
}

在这里插入图片描述
杀进程除了Ctrl+c还有一个方法:
另起一个页面,命令行输入kill -9 进程的pid

4.系统接口 获取父进程pid - getppid

命令行查看系统接口getppid:

man 2 getppid

在这里插入图片描述
注:
手册退出按q

#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
int main()
{
  printf("我的pid是 %d,ppid: %d\n",getpid(),getppid());
  return 0;
}
 

多次运行发现ppid不变
在这里插入图片描述
查看进程,发现父进程是一个bash:
在这里插入图片描述

为什么父进程不变?它是谁?
几乎我们在命令行上执行的所有的指令(你的cmd),都是bash进程的子进程!

5.系统接口 创建子进程 - fork

1、手册

man 2 fork

在这里插入图片描述

2、返回值

下面为手册中返回值解释:
在这里插入图片描述
fork函数是用来创建子进程的,它有两个返回值?

#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
int main()
{
  pid_t id = fork();
  printf("hello world,id: %d\n",id);
  return 0;
}

在这里插入图片描述
父进程返回子进程pid,子进程返回0

同一个id值,使用打印,没有修改,却打出来了不同的值?
现在无法解释,进程地址空间,才能解释!


c语言上,if和else 可以同时执行吗?
c语言中,有没有可能两个以上的死循环同时运行?


#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
int main()
{
  pid_t id = fork();
  if(id==0)
  {
    while(1)
    {
      printf("我是子进程,我的pid:%d,我的父进程是:%d\n",getpid(),getppid());
      sleep(1);
    }
  }
  else 
  {
    while(1)
    {
    printf("我是父进程,我的pid:%d,我的父进程是:%d\n",getpid(),getppid());
    sleep(1);
    }
  }
  printf("hello world,id: %d\n",id);

  return 0;
}

在这里插入图片描述

为什么 fork 给父进程子进程的pid,给子进程 0?
父亲:儿子 = 1:n (n>=1)
为什么给父进程子进程的pid
父进程必须有标识子进程的方案,fork之后,给父进程返回子进程的pid!
为什么给子进程0?
子进程最重要的是要知道自己被创建成功了,因为子进程找父进程成本非常低getppid()


综上得出结论:
fork之后,父进程和子进程会共享代码,一般都会执行后续代码 — printf为什么会打印两次的问题
fork之后,父进程和子进程返回值不同,可以通过不同的返回值来判断,让父子执行不同的代码块!!

3、fork做了什么

fork之后,OS做了什么?
系统多了一个进程:
父进程:task_struct + 进程代码和数据
子进程:task_struct + 子进程的代码和数据

子进程的tastk_struct对象内部数据从哪里来?
基本是从父进程继承下来的

子进程执行代码,计算数据,子进程的代码从哪里来?
和父进程执行同样的代码,fork之后,父子进程代码共享,而数据要各自独立,根据不同的返回值,让不同的进程执行不同的代码(可以用if else 来分流)。

4、基本用法

#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
int main()
{
  pid_t id = fork();
  if(id==0)
  {
  //子进程执行的代码
  }
  else 
  {
  //父进程执行的代码
  }

  return 0;
}

6.进程的状态

1、进程的状态是什么

其实就是个整数 ,int status,在进程的task_struct(进程控制块)里。
int status:
#define RUN 1
#define STOP 2
#define SLEEP 3

2、进程的状态

运行态:进程只要是在运行队列中就叫做运行态,代表我已经准备好了,随时可以调度!
在这里插入图片描述
注:runqueue就是运行队里


终止状态:进程还在,只不过永远不运行了,随时等待被释放!

进程都终止了,为什么不立马释放对应的资源,而是维护一个终止态?
释放要花时间,如果当前系统很忙,系统就没有办法立刻释放,就需要维护一个终止队列,告诉系统,我已经运行结束了,随时可以释放对应的资源,等到系统有空闲的时来释放我吧!


进程阻塞:进程等待某种资源(非CPU)资源没有就绪的时候,进程需要在该资源的等待队列中进行排队,此时进程的代码并没有运行,进程所处的状态就叫做阻塞!

1.一个进程,使用资源的时候,可不仅仅是申请CPU资源
2.进程可能申请更多的其他资源:磁盘,网卡,显卡,显示器资源,声卡/音响

如果申请CPU资源,暂时无法得到满足,需要排队的–运行队列
那么如果申请其他慢设备的资源?—也是需要排队的!
在这里插入图片描述
当访问某些资源(磁盘网卡),该资源如果没有准备好,或者正在给其他进程提供服务,此时:
1.当前进程从runqueue中移除
2.将当前进程放入对应设备的描述结构体中的等待队列

进程等待外部资源的时候,该进程的代码不会被执行,也就是我的进程卡住了就是进程阻塞


进程挂起:短期内不会被调度(你等的资源,短期内不会就绪)进程,OS就会把该进程的代码和数据置换到磁盘上

在这里插入图片描述
如果内存不足怎么办?
操作系统就会帮我们进行辗转腾挪,短期内不会被调度(你等的资源,短期内不会就绪)进程,它的代码和数据依旧在内存中,就是白白浪费空间,OS就会把该进程的代码和数据置换到磁盘上!

往往内存不足的时候,伴随

7.Linux下的进程状态

Linux内核源码:

/*
* The task state array is a strange "bitmap" of
* reasons to sleep. Thus "running" is zero, and
* you can test for combinations of others with
* simple bit tests.
*/
static const char * const task_state_array[] = {
"R (running)", /* 0 */
"S (sleeping)", /* 1 */
"D (disk sleep)", /* 2 */
"T (stopped)", /* 4 */
"t (tracing stop)", /* 8 */
"X (dead)", /* 16 */
"Z (zombie)", /* 32 */
};

1、运行状态 - R

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

int main()
{
  while(1)
  {
    printf("hello wordl!\n");
    sleep(1);
  }
  return 0;
}

运行并查看进程:
在这里插入图片描述
虽然进程一直在执行,但大部分都在sleep.

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

int main()
{
  while(1)
  {
    printf("hello wordl!\n");
    // sleep(1);
  }
  return 0;
}



运行并查看进程:
在这里插入图片描述
原因是这一句 printf(“hello wordl!\n”);,进程大部分时间在等显示器就绪,就绪就打印。

2、阻塞状态 - S (可中断)

“S (sleeping)” 阻塞状态
一般把S状态叫做:浅度睡眠,可中断睡眠


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

int main()
{
  while(1)
  {
  }
  return 0;
}

运行并查看进程:
在这里插入图片描述
这个进程没有访问外设,在访问cpu资源,大概率就是R状态。

“R (running)” 运行态

3、阻塞状态 - D (不可中断)

D (disk sleep)" 阻塞态

D : 深度睡眠,不可被中断睡眠

一般而言,Liunx中,如果我们等待的是磁盘资源,进程阻塞所处的状态就是D。(此时进程在等待外设,切程序不可被中断,如果可以中断,磁盘写入失败,磁盘会把写入失败结果告诉进程时,发现进程已经没了,就会造成数据)

4、僵尸状态- Z 和 死亡状态 - X

X:死亡状态
Z(zombie):僵尸状态

当一个Linux中的进程退出的时候,一般不会进入X状态(死亡,资源可以立马回收),而是进入Z状态。

进程为什么被创建出来?
一定是因为要有任务让这个进程执行,当该进程退出的时候,我们怎么知道,这个进程把任务给我们完成的如何了呢??一般需要将进程的执行结构告诉给父进程 OS

进程进入Z状态,就是为了维护退出信息,可以让父进程或者OS读取的!通过进程等待来进行读取的!

如何模拟僵尸状态?
如果创建子进程,子进程退出了,父进程不退出,也不等待子进程,子进程退出之后所处的状态就是Z。

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
int main()
{
  pid_t id = fork();
  if(id==0)
  {
    //child
    int cnt = 5;
    while(cnt)
    {
      printf("我是子进程,我还剩下%d s\n",cnt--);
      sleep(1);
    }
    exit(0);
  }
  else
  {
    //father
    while(1)
    {
      sleep(1);
    }
  }
  return 0;
}

编译运行并查看进程:

while :; do ps axj|head -1&&ps axj|grep test|grep -v grep;sleep 1; don

在这里插入图片描述

长时间僵尸,有什么问题?
如果没有人回收子进程的僵尸,该状态会一直维护!该进程的相关资源(task_struct)不会被释放,内存泄漏!一般必须要求父进程进行回收(后面说)。

5.停止状态 - T / t

将进程暂停:
方法一:
运行程序,按Ctrl+z。
方法二:
在这里插入图片描述

发送暂停信号给进程

kill -19 pid

在这里插入图片描述

t状态用gdb调试进程,就会出现t状态。

8.孤儿进程

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
int main()
{
  pid_t id = fork();
  if(id==0)
  {
    //child
    int cnt = 5;
    while(cnt)
    {
      printf("我是子进程,我还剩下%d s\n",cnt--);
      sleep(1);
    }
    exit(0);
  }
  else
  {
    //father
    while(1)
    {
      int cnt = 3;
      while(cnt)
      {
        printf("我是父进程,我还剩下%d s\n",cnt--);
         sleep(1);
      }
      exit(0);
    }
  }
  return 0;
}

在这里插入图片描述
上面现象:
前三秒,父进程还没退出,当父进程退出后,子进程的父进程变成了1号进程,再过两秒,子进程退出,被1号进程回收。

结论:
如果父进程提前退出,子进程还在运行,子进程会被1号进程(操作系统)领养,像这样被领养的进程,就叫做孤儿进程。

子进程状态从S+变成S表示什么?
带+号的表示前台进程,可以使用Ctrl+c来杀掉前台进程。
但后台进程就无法用Ctrl+c来杀掉,只能用发送信号来杀掉进程:

kill -9 后台进程的pid

9.进程优先级

1、什么是优先级 vs 权限 (是什么)

优先级是进程获取资源的先后顺序。
权限是能还是不能的问题。

2、为何会存在优先级?(为什么)

排队的本质叫做确定优先级,那为什么要排队------资源不够
系统里面永远都是,进程占大多数,而资源是少数,进程竞争资源是常态,有竞争就需要确认先后,所以要存在优先级。

3、Linux下的优先级的相关概念和操作(怎么办)

查看进程:

ps -al

在这里插入图片描述
优先级由两部分构成:
PRI:priority
NI :nice 进程优先级的修改数据
默认进程优先级是80,数字越小优先级越高
要更改进程优先级,需要更改不是pri,而是Ni。

更改优先级:
命令行输入top->r->输入要更改进程的pid->回车->输入nice的值(范围-20~19一共40个级别)->回车。

在这里插入图片描述
naic的取值范围[-20,19]
priority的取值范围[60,99]

10.竞争性_独立性_并行_并发_进程间切换

竞争性: 系统进程数目众多,而CPU资源只有少量,甚至1个,所以进程之间是具有竞争属性的。为了高效完成任务,更合理竞争相关资源,便具有了优先级

独立性: 多进程运行,需要独享各种资源,多进程运行期间互不干扰,不会因为一个进程挂掉或者异常,而导致其他进程出现问题

并行: 多个进程在多个CPU下分别,同时进行运行,这称之为并行

并发: 多个进程在一个CPU下采用进程切换的方式,在一段时间之内,让多个进程都得以推进,称之为并发

多个进程都在你的系统中运行!= 多个进程都在你的系统中同时运行
不要以为进程一旦占用CPU,就会一直执行到结束,才会释放CPU资源!我们遇到的大部分操作系统都是分时的!操作系统会给每一个进程,再一次调度周期中,赋予一个时间片的概念,在一个是时间段,多个进程都会通过切换交叉的方式,让多个进程代码,在一段时间内都得到推进,这个现象,我们叫做并发。


操作系统,就是简单的根据队列来进行先后调度的吗?如何突然来一个优先级更高的进程?
抢占式内核,正在运行的低优先级进程,如果来个优先级更高的进程,我们的调度会直接把进程从CPU上剥离,放上优先级更高的进程,进程抢占。


进程间切换:

CPU的寄存器是:可以临时的存储数据,非常少,但非常重要。
当进程再被执行的过程中,一定会存在大量是临时数据,会暂时存在CPU内的寄存器中。
我们把进程在运行中产生的各种寄存器数据,叫做进程的上下文数据。
当进程被剥离:需要保存上下文数据
当进程恢复的时候:需要将曾经保存的上下文数据恢复到寄存器中

上下文在哪里保存?
task_struct

三、环境变量

为什么代码运行要带路径,而系统的指令不用带路径?
执行一个可执行程序,前提是要先找到它!
系统中是存在相关的环境变量(PATH),保存了程序的搜索路径的!

1.环境变量操作

查看所有环境变量:

env

显示某一个环境变量:
echo $变量名

echo $PATH

在这里插入图片描述

命令行定义本地变量

a=100

查看本地变量:
set 变量(本地变量和环境变量都可以查到)

set a

注:本地变量不能被env查到

导出环境变量

export bbbb=223

可以被env查到:

env |grep bbbb

在这里插入图片描述

取消环境变量:

unset 环境变量

总结:
查看环境变量: env
查看变量(可以是环境变量也可以是环境变量):set
查看某一个环境命令:eche $环境变量
导出环境变量:export 环境变量
取消环境变量:unset 环境变量

命令行变量分两种:
1.普通变量
2.环境变量(全局)

2.让自己程序和命令一样执行

如何让自己的程序不用带路径?
系统会在环境变量PATH你找可执行程序,如果存在就会执行,例如:cd,ls,touch…也就是说,我们将程序的路径导入PATH里,就可以像系统命令一样执行。

先查找当前程序路径,在导入路径到PATH:

pwd
export PATH=$PATH:路径

是路径的分隔符。
在这里插入图片描述
注:这只是暂时的,重新远程登陆,环境变量就会被重置,导致失效。如果想永久实现这个效果,需要修改配置文件,但不建议,会污染命令池。

3.常见环境命令

PATH : 指定命令的搜索路径
HOME : 指定用户的主工作目录(即用户登陆到Linux系统中时,默认的目录)
SHELL : 当前Shell,它的值通常是/bin/bash。

4.环境变量的C、C++获取方式(代码如何获取环境变量)

1、mian函数参数获取环境变量

main函数可以带参数吗?最多可以带多少?

#include<stdio.h>
int main(int argc,char* argv[])
{
  int  i = 0;
  for(i=0;i<argc;i++)
  {
    printf("argv[%d]:%s\n",i,argv[i]);
  }
  return 0;
}

在这里插入图片描述
我们给main函数传递的agrc,char* argv[],命令行参数传递的是,命令行中输入的程序名和选项!那么意义是什么?

同一个程序,通过传递不同的参数,让同一个程序有不同的执行逻辑,执行结果。Linux系统中会根据不同的选项,让不同的命令,可以有不同的表现!指令中那么多选项的由来和起作用的方式。下面有小实例演示:

想实现命令行计数器:
./myproc -a 10 20
10+20=30
./myproc -s 10 20
10-20=-10

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
void usage()
{

    printf("输入有误,命令使用规则:\n");
    printf("加法:./myproc -a 参数1 参数2\n");
    printf("减法:./myproc -s 参数1 参数2\n");
}
int main(int argc,char* argv[])
{
  if(argc!=4)
  {
    usage();
  }
  else 
  {
    if(strcmp(argv[1],"-a")==0)
    {
      int a = atoi(argv[2]);
      int b =atoi(argv[3]);
      printf("%d+%d=%d\n",a,b,a+b);
    }
    else if(strcmp(argv[1],"-s")==0)
    {
      int a =atoi(argv[2]);
      int b =atoi(argv[3]);
      printf("%d-%d=%d\n",a,b,a-b);
    }
    else 
    {
      usage();
    }
  }
  return 0;
}

在这里插入图片描述


回到第一问,main函数可以带几个参数?
可以带三个,一个进程是会被传入环境变量参数的!

#include<stdio.h>
int main(int agrc,char* argv[],char*env[])
{ 
  for(int i = 0;env[i];i++)
  {
    printf("env[%d]:%s\n",i,env[i]);
  }
  return 0;
}

在这里插入图片描述
扩展:
一个函数在声明是时候没有带参数,可以给这个函数传参吗?
可以。只有fun(void)传参数才会报错。下面演示:

#include<stdio.h>
void fun()
{
  prinf("hello world!\n");
}
int main()
{
  fun(10,29.3,20);
  return 0;
}

在这里插入图片描述

2、通过C语言提供的全局变量获取 - environ

#include<stdio.h>
int main()
{
  extern char** environ;
  for(int i =0;environ[i];i++)
  {
    printf("%d:%s\n",i,environ[i]);
  }
  return 0;
}

在这里插入图片描述

3、获取环境变量函数 - getenv(const char* name)

查看接口:
在这里插入图片描述

#include<stdio.h>
#include<stdlib.h>
int main()
{
  const char* s = getenv("PATH");
  printf("%s\n",s);
  return 0;
}

在这里插入图片描述


为什么要获取环境变量?

一定有特殊用途,比如说:程序可以通过获取环境变量,获取用户信息来确定是否有权限执行。


环境变量是谁给的?

1.命令行启动程序父进程都是bash
2.环境变量是会被子进程继承下去的
3.环境变量是全局变量。
所谓的本地变量,本质就是在bash内部定义的变量,不会被子进程继承下去!

Linux下大部分命令都是通过子进程的方式执行的!
但是,还有一部分命令,不通过子进程的方式执行,而是由bash自己执行(调用自己的对应的函数来完成特定的功能),我们把这种命令叫做内建命令。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1551480.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

智慧工地安全生产与风险预警大平台的构建,需要哪些技术?

随着科技的不断发展&#xff0c;智慧工地已成为现代建筑行业的重要发展趋势。智慧工地方案是一种基于先进信息技术的工程管理模式&#xff0c;旨在提高施工效率、降低施工成本、保障施工安全、提升施工质量。一般来说&#xff0c;智慧工地方案的构建&#xff0c;需要通过集成物…

2024年做视频号小店是不是明智之举?这篇文章告诉你答案

大家好&#xff0c;我是电商糖果 视频号自从去年电商的知名度打开之后&#xff0c;不少朋友都盯上这块肥肉。 要知道现在可是短视频电商的时代&#xff0c;抖音&#xff0c;快手靠做电商赚了不少钱。 视频号又怎么会放过这次的风口呢&#xff1f; 也有不少想做电商的朋友问…

安卓SharedPreferences使用

目录 一、简介二、使用2.1 getSharedPreferences2.2 增加数据2.3 读取数据2.4 删除数据2.5 修改数据2.6 清除数据2.7 提交数据 一、简介 SharedPreferences是Android平台上一个轻量级的存储类&#xff0c;主要是保存一些常用的配置比如窗口状态&#xff0c;一般在Activity、重…

《Linux运维实战:达梦DM8数据库之开启本地归档》

一、归档概述 在达梦数据库归档模式下&#xff0c;数据库同时将重做日志写入联机日志文件和归档日志文件中分别进行存储。采用归档模式会对系统的性能产生影响&#xff0c;然而&#xff0c;当系统一旦出现介质故障&#xff0c;如磁盘损坏时&#xff0c;利用归档日志&#xff0c…

康耐视visionpro-CogToolBlock工具详细说明

CogToolBlock功能: 将多个工具组合在一起完成某个功能&#xff0c;接口简单且可以重用 CogToolBlock操作说明&#xff1a; 1.打开工具栏&#xff0c;双击或点击鼠标拖拽添加CogToolBlock CogToolBlock操作说明 ②.添加输入图像&#xff0c;右键“链接到”或以连线拖拽的方式选…

【JavaWeb】Day22.maven安装介绍

目录 一.初识Maven 什么是maven? Maven的作用 二.Maven概述 1. Maven介绍 2.Maven模型 3. Maven仓库 三. Maven安装 1.下载 2. 安装步骤 1. 解压安装 2. 配置本地仓库 3.配置阿里云私服 4. 配置Maven环境变量 一.初识Maven 什么是maven? Maven是apache旗下的一个…

稀碎从零算法笔记Day27-LeetCode:螺旋矩阵

题型&#xff1a;矩阵(二维数组)、边界问题 链接&#xff1a;54. 螺旋矩阵 - 力扣&#xff08;LeetCode&#xff09; 来源&#xff1a;LeetCode 题目描述 给你一个 m 行 n 列的矩阵 matrix &#xff0c;请按照 顺时针螺旋顺序 &#xff0c;返回矩阵中的所有元素。 很有趣的…

Transformer的前世今生 day11(Transformer的流程)

Transformer的流程 在机器翻译任务中&#xff0c;翻译第一个词&#xff0c;Transformer的流程为&#xff1a; 先将要翻译的句子&#xff0c;一个词一个词的转换为词向量送入编码器层&#xff0c;得到优化过的词向量以及K、V&#xff0c;将K、V送入解码器层&#xff0c;并跟解码…

Games104 听后笔记

1、为什么UE5要自己写一套STL库 因为传统的STL库中&#xff0c;例如&#xff1a;vector&#xff0c;它一般采用的是双倍扩容法&#xff0c;加入1000个数据装满了&#xff0c;现在需要又加一个&#xff0c;那么就开辟了2000个数据的空间&#xff0c;那么当前就又999的数据空间暂…

【差分约束+并查集】第十三届蓝桥杯省赛C++ A组 Java A组/研究生组《推导部分和》(C++)

【题目描述】 【输入格式】 【输出格式】 【数据范围】 【输入样例】 5 3 3 1 5 15 4 5 9 2 3 5 1 5 1 3 1 2 【输出样例】 15 6 UNKNOWN 【思路】 题解来源&#xff1a;AcWing 4651. $\Huge\color{gold}{推导部分和}$ - AcWing 【代码】 #include<bits/stdc.h> #define…

CentOS7.7安装XIAOJUSURVEY问卷系统|表单收集|简单考题

XIAOJUSURVEY问卷系统&#xff0c;适用于市场调研、客户满意度调研、在线考试、投票、报道、测评等众多场景。数据能力上&#xff0c;经过上亿量级打磨&#xff0c;沉淀了分题统计、交叉分析、多渠道分析等在线报表能力&#xff0c;快速满足专业化分析。 一、在CentOS7.7上安装…

设计模式系列之--观察者模式-画图讲解

观察者模式已经是比较常见的设计模式了&#xff0c;并且使用的频率也比较高, 那么我们什么时候用&#xff0c;简而言之就是&#xff0c;当我们一个主体改变&#xff0c;它所有下级要跟着改变的时候就需要用了&#xff0c;比如&#xff1a;换肤&#xff0c;全局数据修改&#x…

原型链-(前端面试 2024 版)

来讲一讲原型链 原型链只存在于函数之中 四个规则 1、引用类型&#xff0c;都具有对象特性&#xff0c;即可自由扩展属性。 2、引用类型&#xff0c;都有一个隐式原型 __proto__ 属性&#xff0c;属性值是一个普通的对象。 3、引用类型&#xff0c;隐式原型 __proto__ 的属…

Windows安装Odoo结合内网穿透实现公网访问本地企业管理系统

文章目录 前言1. 下载安装Odoo&#xff1a;2. 实现公网访问Odoo本地系统&#xff1a;3. 固定域名访问Odoo本地系统 前言 Odoo是全球流行的开源企业管理套件&#xff0c;是一个一站式全功能ERP及电商平台。 开源性质&#xff1a;Odoo是一个开源的ERP软件&#xff0c;这意味着企…

python、execl数据分析(数据描述)

一 python 1.各函数 1.1python库的安装与导入 #pip install os#pip install matplotlib#pip install seaborn#pip install scikit-learn#pip install scipy#修 改 工 作 目 录import osos.getcwd () # 查看当前工作环境os.chdir( F :\my course\database ) # 修改工作环境o…

网络稳定性(蓝桥省赛)

0网络稳定性 - 蓝桥云课 (lanqiao.cn) 知识点&#xff1a;克鲁斯卡尔生成树&#xff0c;lca&#xff0c;倍增 最小生成树的模板&#xff1a;最小生成树【模板】-CSDN博客 题解代码如下&#xff1a; #include<bits/stdc.h> using namespace std; const int N3e5100; co…

智慧光伏:企业无纸化办公

随着科技的快速发展&#xff0c;光伏技术不仅成为推动绿色能源革命的重要力量&#xff0c;更在企业办公环境中扮演起引领无纸化办公的重要角色。智慧光伏不仅为企业提供了清洁、可持续的能源&#xff0c;更通过智能化的管理方式&#xff0c;推动企业向无纸化办公转型&#xff0…

CBO VS ABO,哪种策略才更能优化FB广告?

海外创业时&#xff0c;FB广告无疑是吸引目标受众、推动业务增长的重要渠道之一&#xff01;然而令大家头疼的却是在CBO与ABO的选择上&#xff0c;今天就带大家一起解读这两种常见的广告策略。了解两者之间的区别、优缺点及适用场景。 CBO 和 ABO 分别是什么&#xff1f; CBO&a…

网络面试——浏览器输入url到显示主页的过程

浏览器输入URL到显示主页的过程通常可以分为以下步骤&#xff1a; 1. **URL解析**&#xff1a; - 当用户在浏览器的地址栏中输入URL时&#xff0c;浏览器会首先对该URL进行解析。 - 解析URL包括识别协议&#xff08;例如HTTP、HTTPS&#xff09;、主机名&#xff08;例如…

Redis项目实战

本文用用代码演示Redis实现分布式缓存、分布式锁、接口幂等性、接口防刷的功能。 课程地址&#xff1a;Redis实战系列-课程大纲_哔哩哔哩_bilibili 目录 一. 新建springBoot项目整合Redis 二. Redis实现分布式缓存 2.1 原理及好处 2.2 数据准备 2.3 Redis实现分布式缓存…