【Linux第五课-进程上】PCB内部属性、标识符、进程状态、Linux下的进程状态、进程的优先级、Linux进程的调度与切换

news2024/11/19 8:33:42

目录

  • 体系结构 -- 硬件上
  • 操作系统 -- 软件上
  • 进程
    • PCB内部属性
      • 1、在linux里面看程序
      • 2、标识符
        • 获取程序的标识符
        • 父进程标识符 PPID
        • 查看进程的另一种方法
        • 通过系统调用创建进程 - fork
          • 杀掉一个进程
          • for循环创建多个代码
      • 3、进程状态
        • 进程排队 - 队列
        • 教程上关于进程状态表述
          • 运行
          • 阻塞
          • (阻塞)挂起
        • Linux下的具有进程状态
        • R(running)运行状态
        • S(sleep)睡眠状态
        • D(Disk sleep)磁盘休眠状态
        • t(stopped)暂停状态
        • T(tracing stop)暂停状态
        • Z(zombie)僵尸状态
          • 孤儿进程
        • X(dead)死亡状态
        • 信号
    • 进程的优先级
      • 是什么?
      • 为什么存在优先级
      • 调整优先级
    • Linux的调度与切换
      • 概念
      • 进程切换
      • 进程调度
    • PCB外部,整体使用

体系结构 – 硬件上

1、冯诺依曼体系结构
在这里插入图片描述
独立
CPU:运算器(算数和逻辑运算)+控制器(协调CPU内部之间 信息流动)
输入设备:话筒、摄像头、键盘、鼠标、磁盘、网卡等
输出设备:声卡、显卡、网卡、磁盘、显示器、打印机等
有的设备只做输入,只做输出,有的即做输入又做输出
存储器:内存(掉电易使)
设备是链接的:总线(主板)链接起来
链接不是目的,是手段。目的是设备之间的数据流动(本质:设备之间会进行数据的来回拷贝)

操作系统 – 软件上

进行软硬件管理的软件
在这里插入图片描述

什么时候读、什么时候写、都多少、写多少是操作系统管的
对任何事务做管理:先描述,在管理

操作系统给用户提供一系列的系统调用接口对操作系统内部的数据进行访问,不允许用户直接访问操作系统内部数据

系统调用接口,就是C语言设计的函数,系统调用函数(函数就有输入和输出)
操作系统给用户提供:数据方面的支持、功能方面的支持

进程

教材观点:
加载到内存的程序 – 进程
正在运行的程序

事实
(1)我们可以启动多个程序(每个程序都有一个exe) — 我们将多个exe加载到内存
(2)操作系统需要管理多个加载到内存的程序
(3)操作系统如何管理加载到内存的程序?先描述,在组织
一个加载到内存的程序我们称为进程

struct xxx
{
	//状态
	//优先级
	//内存指针字段
	//标识符
	//……包含进程几乎所有的属性字段
	struct xxx* next;
}

上述的描述进程的结构体,我们称为PCB(process ctrl block)进程控制块

struct PCB
{
	//状态
	//优先级
	//内存指针字段
	//标识符
	//……包含进程几乎所有的属性字段
	struct PCB* next;
}

对进程的管理转换成对PCB对象的管理,也就是对链表的增删查改

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

PCB,操作系统学科的叫法
具体的linux,PCB称为task_struct,操作系统内部的数据

PCB内部属性

1、标识符
2、状态
3、优先级
4、程序计数器:程序中即将要被执行的指令的地址
5、内存指针:找到代码和数据的指针
6、I/O状态信息:
7、记账信息

1、在linux里面看程序

创建myprocess.c
在这里插入图片描述
创建Makefile
在这里插入图片描述
运行程序

第一条程序是myprocess进程
第二条程序是grep本身是一个指令,也就是一个程序,它是包含myprocess
几乎所有的独立的指令,就是程序,运行起来也要变成进程
在这里插入图片描述
看进程结束的过程

while :; do ps ajx | head -1 && ps ajx | grep myprocess | grep -v grep; sleep 1; done

在这里插入图片描述

1、只有打印到显示屏上的内容才能被重定位和追加重定位
(1) '>':重定向
(2)‘>>’:追加重定向
blog.csdnimg.cn/direct/91879d6b99a14e19b5761449f2343282.png)
在这里插入图片描述
2、‘echo’:后面跟着string直接打印string,后面跟着$sht则打印变量sht的值
3、'|':表示管道,上一条命令的输出,作为下一条命令参数进行传递,如:ls | grep “aa”,在ls的输出中查找aa字符串。
4、'head':打印一个文件的前多少行
(1)head:默认打印前十行
(2)head -n:打印前n行
5、&&:表示前一条命令执行成功时,才执行后一条命令 ,如 echo '1‘ && echo ‘2’
在这里插入图片描述
6、grep
(1)grep xxx:过滤出来包含xxx的
(2)grep -v grep:反向过滤,不把含义grep的过滤出来
在这里插入图片描述

2、标识符

PID就是标识符

ps axj

COMMAND代表你这个进程在启动的时候对应的可执行程序是谁
在这里插入图片描述

获取程序的标识符

函数调用

getpid

man getpid
在这里插入图片描述

  1 #include<stdio.h>
  2 #include<unistd.h>
  3 #include<sys/types.h>
  4 
  5 int main()
  6 {
  7     pid_t id = getpid();
  8     printf("%d\n", id);
  9     printf("hello zyh\n");
 10     return 0;                                                                 
 11 }

在这里插入图片描述

在Linux中,普通进程,一般都有父进程

父进程标识符 PPID
getppid

在这里插入图片描述

  1 #include<stdio.h>                                                             
  2 #include<unistd.h>
  3 #include<sys/types.h>
  4 
  5 int main()
  6 {
  7     pid_t id = getpid();
  8     pid_t fid = getppid();
  9     printf("id:%d\n", id);
 10     printf("fid:%d\n", fid);
 11     printf("hello zyh\n");
 12     return 0;
 13 }

每一次启动进程的pid都会变化,因为我们每次启动的都是一个新进程

其中bash就是命令行解释器
在这里插入图片描述

查看进程的另一种方法

ls
-l 参数 以详细格式列表
-d 参数 仅列当前目录本身

通过/proc系统文件夹进行查看
在这里插入图片描述
当我们要查看某特定进程
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

为何删了之后还能正常运行,因为程序正在运行被加载到了内存,删除磁盘上的可执行程序没有影响
cwd是当前工作目录

fopen(“./文件名”, “w”);
如果没有此文件就在当前路径下创建
改变当前的工作目录:chdir()
在这里插入图片描述
在这里插入图片描述

当前路径:当前进程所在的路径cwd
在这里插入图片描述

  1 #include<stdio.h>
  2 #include<unistd.h>
  3 #include<sys/types.h>
  4 
  5 int main()
  6 {
  7     pid_t pid = getpid();
  8     printf("pid: %d\n", pid);
  9 
 10     FILE *fp = fopen("./zyh.txt","w");
 11     if(fp == NULL) return 0;
 12     printf("zyh.txt文件创建成功!\n");                                        
 13     fclose(fp);
 14     sleep(20);
 15     return 0;
 16 }

如果进程的所在路径cwd被修改,那么文件也会被创建在修改后的路径
改变当前的工作目录:chdir()
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

  1 #include<stdio.h>
  2 #include<unistd.h>
  3 #include<sys/types.h>
  4 
  5 int main()
  6 {
  7     pid_t pid = getpid();
  8     printf("pid: %d\n", pid);
  9     sleep(20);
 10     printf("修改当前路径\n");
 11     chdir("/home/hui");                                                       
 12     printf("修改当前路径成功\n");
 13     sleep(20);
 14     FILE *fp = fopen("./zyh.txt","w");
 15     if(fp == NULL) return 0;
 16     printf("zyh.txt文件创建成功!\n");
 17     fclose(fp);
 18     sleep(20);
 19     return 0;
 20 }
通过系统调用创建进程 - fork

在这里插入图片描述
对于fork的返回:对于父进程返回创建进程的id,对于子进程返回0

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

一般而言,我们想让父子做不同的事情
pid都是大于等于0的数字

父进程先被创建了
在这里插入图片描述
此时子进程也被创建了
在这里插入图片描述
在这里插入图片描述

进程 = 内核数据结构 + 可执行程序的代码和数据
创建子进程时,是以父进程为模板的。内核数据结构大部分和父进程一样,但也有些少部分不一样(如,pid、ppid)

(1)fork为何会返回两个值为什么会这样?
把子进程的pid返回给父进程,目的是方便父进程对子进程的控制和唯一性确认。子进程不需要这些,只需要知道创建成功没成功,因此返回0就可以了(父:子 = 1:n,子进程找父进程是唯一的,父进程找子进程就需要pid)
(2)fork为何会返回两次?
如果一个函数,已经运行到了return的时候,说明这个函数的核心逻辑已经做完了
在调用fork函数的时候,运行到return这条语句之前,子进程就已经被创建,因此return id这条语句是同时被父进程和子进程执行的
在这里插入图片描述

(3)id怎么可能同一个变量,既大于0,又等于0

一个进程崩溃了,不会影响其他进程
进程(任意)之间是具有独立性的,互相不受影响。(os在设计的时候就必须保证的)

杀掉一个进程
kill -9 进程id

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

linux中可以使用同一个变量名,表示不同的内存
当代码被编译成二进制,代码中的变量名就不在了

for循环创建多个代码
  1 #include <stdio.h>
  2 #include <unistd.h>
  3 #include <stdlib.h>
  4 #include <sys/types.h>
  5 const int num = 10;
  6 
  7 void work()
  8 {
  9     int x = 10;
 10     while(x > 0)
 11     {
 12         printf("I am a child process, my id: %d\n",getpid());
 13         sleep(1);
 14         --x;
 15     }
 16 }
 17 
 18 int main()
 19 {
 20     for(int i = 0; i < num; i++)
 21     {
 22         pid_t id = fork();
 23         sleep(1);
 24         if(id < 0) break;                                             
 25         else if(id == 0)
 26         {
 27             //子进程
 28             work();
 29             exit(1);
 30         }
 31         //父进程
 32         printf("creat %d child process, subid:%d\n", i, id);
 33     }
 34     sleep(20);
 35     return 0;
 36 }

正在创建子进程
在这里插入图片描述
正在杀死子进程
在这里插入图片描述

3、进程状态

进程排队 - 队列

进程排队一定是在等待某种资源

进程不是一直在运行的,进程放在CPU上,也不会一直运行 — 时间片
排队:是进程的task_struct在排队

Linux中进程pcb的排序
在这里插入图片描述

教程上关于进程状态表述

运行、阻塞、挂起
所谓的状态,就是一个整型变量,再task_struct中的一个整型变量

#define New 1
#define Ready 2
#define running 3
#define block 4

struct task_struct
{
	int status;
	……
}
运行

把进程的PCB放到一个CPU的运行队列中,我们就称为这个队列的运行状态
在这里插入图片描述

一个CPU一个运行队列

阻塞

在这里插入图片描述
当我们的进程在进行等待软硬件资源的时候,资源如果没有就绪,我们进程的task_struct只能

1、将自己设置为阻塞状态
2、将自己的pcb连入等待的资源提供的等待队列

状态的变换,就是把进程的PCB放到不同的队列中

(阻塞)挂起

在这里插入图片描述

挂起状态
前提:计算机资源(eg:内存资源)已经比较吃紧了
阻塞挂起:当进程在阻塞的状态下,资源吃紧了,操作系统就会把阻塞进程的代码和数据从内存写回到磁盘的swap分区

进程的PCB(task_struct)不会换出
创建进程时先创建对应进程的PCB(内核数据结构)

Linux下的具有进程状态

在这里插入图片描述

R(running)运行状态

并不意味着进程一定在运行中,它表明进程要么是在运行中要么在运行队列里。
在这里插入图片描述

代码在运行为何显示是S,因为代码里面只有一行printf,printf导致进程大部分时间都在等待
在这里插入图片描述
把进程改成一个死循环就是R状态了
在这里插入图片描述
在这里插入图片描述

+”:是指这个进程在前台,运行此进程时,无法执行其他命令
./myprocess &后台进程
(1)后台进程ctrl+c无法杀掉,只能kill -9 进程id

前台进程
在这里插入图片描述
后台进程
在这里插入图片描述

S(sleep)睡眠状态

意味着进程在等待事件完成,也就是一种阻塞状态,Linux中也称为浅度睡眠

ctrl+c可以结束进程

在这里插入图片描述

D(Disk sleep)磁盘休眠状态

称为不可中断睡眠,又称深度睡眠D状态也是阻塞状态,有些进程执行的内容很重要,操作系统不能把它杀死

t(stopped)暂停状态

让进程处于暂停状态,当某些进程操作比较危险,操作系统会将其暂停。也是阻塞状态
(1)程序开始运行,创建了进程此时进程是前台进程
在这里插入图片描述
(2)kill -9 进程id对进程进行暂停
在这里插入图片描述
(3)kill -19 进程id对进程进行启动,再次启动的进程有前台进程变为后台进程

在这里插入图片描述

T(tracing stop)暂停状态

进程处于被追踪状态,等待gdb给的控制命令,gdb不让进程跑了。也是阻塞状态
(1)在生成可执行程序的时候注意加-g
在这里插入图片描述
(2)进入gdb; l + 行号:从第几行开始显示代码
在这里插入图片描述
(3)p:打断点; r:运行到断点
此时的进程就是t状态,等待gdb的下一步指令
在这里插入图片描述

Z(zombie)僵尸状态

也是终止状态,当进程完成时或发生意外,代码和数据可以释放,但进程的PCB不能被释放,父进程或操作系统还需要去读其退出信息

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

int main()
{
	pid_t id = fork();
	//子进程
	if(id == 0)
	{
		int cnt = 5;
		while(cnt)
		{
			printf("I am child, pid: %d, ppid: %d\n", getpid(), getppid());
			sleep(1);
			cnt--;
		}
		exit(0); //子进程退出
	}
	//只有父进程,父进程一直死循环就不会读取子进程的退出信息,子进程就处于僵尸状态
	while(1)
	{
		printf("I am father, pid: %d, ppid: %d\n", getpid(), getppid());
		sleep(1);
	}
	return 0;
}

在这里插入图片描述

为何会有Z状态?
创建进程是希望这个进程给用户完成工作的,子进程必须有结果数据,PCB中的。
什么是Z?
进程已经退出,但当前进程的状态需要自己维持住,供上层读取,必须处于Z
如果父进程就不读取?
僵尸状态会一直存在,task_struct对象也要一直存在,都是要占据内存的。内存泄漏
最初创的进程的父进程是bash,会自动回收退出信息,如果在自己创建的进程下面再fork一个子进程,此时子进程的父进程不会自动回收退出信息

bash进程会自动读取其下面子进程的退出信息,但这里创建的father进程不会自动读出子进程的退出信息
在这里插入图片描述
在这里插入图片描述

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/wait.h>

int main()
{
	pid_t id = fork();
	//子进程
	if(id == 0)
	{
		int cnt = 5;
		while(cnt)
		{
			printf("I am child, pid: %d, ppid: %d\n", getpid(), getppid());
			sleep(1);
			cnt--;
		}
		exit(0); //子进程退出
	}
	//只有父进程,父进程一直死循环就不会读取子进程的退出信息,子进程就处于僵尸状态
	int cnt = 10;
	while(cnt)
	{
		printf("I am father, pid: %d, ppid: %d\n", getpid(), getppid());
		sleep(1);
		cnt--;
	}

	//父进程读取子进程的退出信息
	wait(NULL);
	printf("father wait child done...\n");

	sleep(5);

孤儿进程

一个进程的父进程先退出了,那该进程会被1号进程领养,1号进程是操作系统

一个进程被领养后,不仅变成孤儿进程,还会变成后台进程

在这里插入图片描述

    pid_t id = fork();
	//子进程
	if(id == 0)
	{
		while(1)
		{
			printf("I am child, pid: %d, ppid: %d\n", getpid(), getppid());
			sleep(1);
			cnt--;
		}
		//exit(0); //子进程退出
	}
	//只有父进程,父进程一直死循环就不会读取子进程的退出信息,子进程就处于僵尸状态
	int cnt = 10;
	while(cnt)
	{
		printf("I am father, pid: %d, ppid: %d\n", getpid(), getppid());
		sleep(1);
		cnt--;
	}

X(dead)死亡状态

终止状态,是一个瞬时状态很难查到

信号
kill -l

9:SIGKILL
19:SIGSTOP
18:SIGCONT
在这里插入图片描述

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

进程的优先级

是什么?

前提:进程要访问某种资源,进程通过一定的方式(排队),确认享受资源的先后顺序

优先级和权限的区别
优先级:你先还是我先的问题
权限:能不能的问题

为什么存在优先级

资源过少,相对的概念
PRI (Priority):进程的优先级

linux的优先级在进程运行中或运行前是可以被修改的,优先级范围[60,99]–>40
nice值为**[-20, 19]**
数字越小优先级越高

在这里插入图片描述

调整优先级

1、top进入任务管理器
2、r(renice)-> 输入对于pid -> 要修改的nice -> q退出
输入r之后的界面
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

Linux系统允许用户调整优先级,但是不能直接让修改pri,而是修改nice值
nice:进程优先级的修正数据[-20, 19]
pri = pri(old) + nice pro(old)每次都是80

为何优先级调整在60-99之间
如果不加限制,将自己进程的优先级调整的非常高,别人的优先级调成非常低
优先级较高的进程,优先得到资源,后面还有源源不断的进程产生。常规进程很难享受到CPU资源 — 进程饥饿

Linux的调度与切换

概念

1、进程在运行的时候,放在CPU上,直接必须把进程跑完,才行吗?
不行,现在操作系统都是基于时间片进行轮转执行的
2、
竞争性: 系统进程数目众多,而CPU资源只有少量,甚至1个,所以进程之间是具有竞争属性的。为了高效完成任务,更合理竞争相关资源,便具有了优先级
独立性: 多进程运行,需要独享各种资源,多进程运行期间互不干扰
并行: 多个进程在多个CPU下分别,同时进行运行,这称之为并行
并发: 多个进程在一个CPU下采用进程切换的方式,在一段时间之内,让多个进程都得以推进,称之为并发

进程切换

进程在运行时,会产生大量的临时数据放到CPU的寄存器中

所有的保存都是为了最终的恢复,所有的恢复,都是为了继续上一次的运行位置继续运行。可以认为寄存器里的数据保存在PCB保护上下文
虽然寄存器数据放在一个共享的CPU里面,但是所有的数据,其实都是被进程私有的

CPU内部的所有临时数据,称作进程的硬件上下文
CPU内的寄存器只有一套,寄存器内保存的数据可以有多套

进程调度

Linux实现进程调度的算法,考虑优先级、饥饿、效率

分时操作系统:公平,每个进程在一定时间段内享受到资源。即便有优先级,大家优先级也不明显。eg:互联网买东西,大家优先级都一样
实时操作系统:进程跑起来必须跑完才能跑下一个,必须严格按照顺序跑,有更高优先级的进程允许插队。 eg:做车载系统,一脚油门下去必须立马反应,不能基于时间片慢慢跑

0-99不考虑实时优先级
100-139:这四十个对应着进程的优先级**[60,99]**
在这里插入图片描述

每次从头查数组各个位置是否为空还是很麻烦的int bitmap[5]
32*5=160
比特位的位置,表示哪个队列
比特位的内容,表示该队列是否为空
检测那个队列中是否有进程,检测对应的比特位是否为1

如果一直有高优先级的进程排队就会产生饥饿问题,解决方法:过期进程和活跃进程
CPU从活跃队列选择进程,新来的进程在过期队列
在这里插入图片描述

struct q* activestruct q* expired
CPU只会去活跃队列里面拿进程,当进程运行时间片结束或运行结束或新建进程,操作系统会将其放入到过期队列

struct q* active = &array[0]
struct q* expired = & array[1]

在这里插入图片描述

活跃队列里面的进程不断增多,过期队列中的进程不断减少,对后只需要对active和expired进行交换指针的内容即可

swap(&active, &expired)

PCB外部,整体使用

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

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

相关文章

ubuntu2204操作系统使用可执行文件方式安装docker-compose记录

文章目录 前言一、版本信息二、操作步骤2.1 确认版本2.2 下载部署2.官网参考3.docker-compose版本 总结 前言 记录一下在ubuntu操作系统上使用下载可执行文件方式部署docker-compose的记录。 一、版本信息 操作系统版本&#xff1a; docker-compose版本&#xff1a; 备注&…

RISC-V开发 linux下GCC编译自定义指令流程笔记

第一步&#xff1a;利用GCC提供了内嵌汇编的功能可以在C代码中直接内嵌汇编语言 第二步&#xff1a;利用RSIC-V的中的.insn模板进行自定义指令的插入 第三步&#xff1a;RISC-V开发环境的搭建 C语言插入汇编 GCC提供了内嵌汇编的功能可以在C代码中直接内嵌汇编语言语句方便了…

Vue3.0面试题汇总

Composition API 可以说是Vue3的最大特点&#xff0c;那么为什么要推出Composition Api&#xff0c;解决了什么问题&#xff1f; 通常使用Vue2开发的项目&#xff0c;普遍会存在以下问题&#xff1a; 代码的可读性随着组件变大而变差每一种代码复用的方式&#xff0c;都存在缺…

【Linux基础IO】Linux IO编程入门:揭秘动态库与静态库的秘密

&#x1f4dd;个人主页&#x1f339;&#xff1a;Eternity._ ⏩收录专栏⏪&#xff1a;Linux “ 登神长阶 ” &#x1f921;往期回顾&#x1f921;&#xff1a;Linux Shell &#x1f339;&#x1f339;期待您的关注 &#x1f339;&#x1f339; ❀Linux基础IO &#x1f4d2;1. …

Mysql梳理10——使用SQL99实现7中JOIN操作

10 使用SQL99实现7中JOIN操作 10.1 使用SQL99实现7中JOIN操作 本案例的数据库文件分享&#xff1a; 通过百度网盘分享的文件&#xff1a;atguigudb.sql 链接&#xff1a;https://pan.baidu.com/s/1iEAJIl0ne3Y07kHd8diMag?pwd2233 提取码&#xff1a;2233 # 正中图 SEL…

Git 的安装和配置

Git 是跨平台的&#xff0c;可以在 Windows&#xff0c;Linux、Unix 和 Mac 各几大平台上使用 由于笔者主要是使用 Windows&#xff0c;其他平台下安装 Git 的方法暂且不表&#xff08;可参考廖雪峰老师的博客&#xff1a;安装 Git&#xff09; ‍ Windows 安装 Git 从 Git…

【案例73】Uclient无法读取https地址添加应用

问题现象 客户做了一个https的域名转换&#xff0c;网页端是正常访问的&#xff0c;但是在uclient里面添加应用就不行了,出来两个不对的应用&#xff0c;也安装不了&#xff0c;提示失败。 问题分析 点击添加应用发现&#xff0c;本来添加地址是https://域名:外网端口&#x…

【C++报错已解决】std::bad_alloc

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏: 《C干货基地》《粉丝福利》 ⛺️生活的理想&#xff0c;就是为了理想的生活! 专栏介绍 在软件开发和日常使用中&#xff0c;BUG是不可避免的。本专栏致力于为广大开发者和技术爱好者提供一个关于BUG解决的经…

海外媒体投稿:如何运用3种国内外媒体套餐发稿突出重围?

在当今瞬息万变的经营环境中&#xff0c;突出重围营销推广是每家企业都需要思考的问题。为了能突出重围并提升影响力&#xff0c;国内外媒体套餐内容成为了一个非常受欢迎的挑选。下面我们就为大家讲解如何运用三种不同种类的国内外媒体套餐内容来推广突出重围。 2.微博营销新浪…

GIS在构建虚拟世界中的新机遇

地理信息系统&#xff08;GIS&#xff09;技术在构建虚拟世界中扮演着越来越重要的角色。随着数字孪生、虚拟现实&#xff08;VR&#xff09;、增强现实&#xff08;AR&#xff09;和混合现实&#xff08;MR&#xff09;等技术的发展&#xff0c;GIS为虚拟世界提供了地理信息和…

QT开发:基于Qt实现的交通信号灯模拟器:实现一个带有倒计时功能的图形界面应用

介绍 本文将介绍如何使用Qt框架实现一个简单的交通信号灯控制程序。本程序包括一个图形界面&#xff0c;显示红、黄、绿三色信号灯&#xff0c;并通过定时器控制信号灯的切换。同时&#xff0c;我们还将实现一个带有按钮的界面&#xff0c;用于展示信号灯的状态。 1. 安装Qt开…

Linux下的git开篇第一文:git的意义

目录 1.git版本控制器 2.git gitee&&github 3.Linux中gitee的使用 &#xff08; 三板斧 git add git commit -m " " git push &#xff09; 4.git log 查看之前的修改信息 &#xff08;所有提交日志&#xff09; 5.git status 查看工作目录与本地…

三防手机也能实现双卫星通信?智慧应急再添一员猛将!

随着可重复使用运载火箭技术取得显著进展&#xff0c;民营航天快速发展&#xff0c;商业卫星的发射成本不断降低&#xff0c;卫星通信全面普及的时代即将来临。遨游通讯提前布局双卫星通信技术&#xff0c;AORO M5-5G三防手机集成了天通卫星电话与北斗短报文两大国产通信技术。…

怎么将excel表格数据自动生成二维码?批量静态二维码转换的方法

在日常生活中&#xff0c;遇到需要大量二维码制作需求时&#xff0c;比如说需要给同一批产品生成不同编号的二维码时&#xff0c;有什么方法能够快速批量生成二维码呢&#xff1f;如果一个个二维码去制作不仅需要浪费大量的时间&#xff0c;而且也比较容易出错&#xff0c;那么…

MATLAB读取TIF文件,并可视化

在GIS领域&#xff0c;TIF文件则常用于存储地图、地形图等地理空间数据&#xff0c;TIF文件用于地理信息系统时&#xff0c;它通常包含地理坐标、投影信息等地理元数据&#xff0c;这些元数据使得图像能够与地理信息系统无缝集成&#xff0c;便于进行地理定位和分析。 1.读取T…

初始C++模板

1.泛型编程 1.1什么事泛型编程 在学习C语言时&#xff0c;我们时常会有这样的烦恼&#xff1a; 在针对每一种不同的类型变量进行函数传参或者是运算处理时&#xff0c;我们总是编写不同的函数或者是进行不同的处理&#xff0c;才能达到目的&#xff0c;这时&#xff0c;我们…

【JavaEE初阶】深入解析单例模式中的饿汉模式,懒汉模式的实现以及线程安全问题

前言&#xff1a; &#x1f308;上期博客&#xff1a;【JavaEE初阶】深入理解wait和notify以及线程饿死的解决-CSDN博客 &#x1f525;感兴趣的小伙伴看一看小编主页&#xff1a;GGBondlctrl-CSDN博客 ⭐️小编会在后端开发的学习中不断更新~~~ &#x1f973;非常感谢你的…

YOLOv8改进 - 注意力篇 - 引入LSKA注意力机制

一、本文介绍 作为入门性篇章&#xff0c;这里介绍了LSKA注意力在YOLOv8中的使用。包含LSKA原理分析&#xff0c;LSKA的代码、LSKA的使用方法、以及添加以后的yaml文件及运行记录。 二、LSKA原理分析 LSKA官方论文地址&#xff1a;LSKA文章 LSKA注意力机制&#xff08;大可分…

胤娲科技:揭秘AI记忆宫殿—LLM如何用动画玩转乔丹打篮球的秘密

当AI遇上“乔丹打篮球”&#xff0c;真相竟然藏在动画里&#xff1f; 想象一下&#xff0c;你向一位AI大模型轻声询问&#xff1a;“迈克尔・乔丹从事的体育运动是……”几乎在瞬间&#xff0c;它就自信满满地回答&#xff1a;“篮球&#xff01;” 这一刻&#xff0c;你是否曾…

ROS理论与实践学习笔记——2 ROS通信机制之服务通信

服务通信也是ROS中一种极其常用的通信模式&#xff0c;服务通信是基于请求响应模式的&#xff0c;是一种应答机制。也即: 一个节点A向另一个节点B发送请求&#xff0c;B接收处理请求并产生响应结果返回给A&#xff0c;用于偶然的、对时时性有要求、有一定逻辑处理需求的数据传输…