【Linux】进程的概念 进程状态 进程优先级
Content
- 一、什么是进程
- 1. 进程的概念
- 2. 进程的描述 - 进程控制块(PCB)
- 3. Linux下的进程
- 二、进程状态
- 1. 教科书中的进程状态
- 运行状态
- 阻塞状态
- 挂起状态
- 2. Linux下的进程状态
- R(running)- 运行状态
- S(sleeping) - 睡眠状态
- D(disk sleep)- 磁盘休眠状态
- T(stopped)- 停止状态
- t(tracing stop)- 追踪暂停状态
- X(dead)- 死亡状态
- > 两种特殊的进程 <
- 1. 僵尸进程
- 2. 孤儿进程
- 三、进程的优先级
- 1. 什么是优先级
- 2. 为什么要有优先级
- 3. Linux中优先级的特点
- 四、进程的其他概念
[!abstract] 进程的学习:
- 认识冯诺依曼系统
- 操作系统概念与定位
- 深入理解进程概念,了解PCB
- 学习进程状态,学会创建进程,掌握僵尸进程和孤儿进程,及其形成原因和危害
- 了解进程调度,Linux进程优先级,理解进程竞争性与独立性,理解并行与并发
- 理解环境变量,熟悉常见环境变量及相关指令, getenv/setenv函数
- 理解C内存空间分配规律,了解进程内存映像和应用程序区别, 认识地址空间
- 学习进程创建,fork/vfork
- 学习到进程等待
- 学习到进程程序替换, 微型shell,重新认识shell运行原理
- 学习到进程终止,认识$?
一、什么是进程
1. 进程的概念
- 课本概念:进程就是被加载到内存中的程序,或者被运行起来的程序就叫做进程
- 操作系统内核观点:进程=可执行程序+进程控制块(PCB)。
2. 进程的描述 - 进程控制块(PCB)
进程控制块PCB (Process Control Block),是操作系统中用于描述进程的工具,其中包含的是进程属性的集合。
Linux操作系统下的PCB是 task_struct,它是Linux内核的一种数据结构,其内容可以分为如下几类:
- 标示符: 描述本进程的唯一标示符,用来区别其他进程。
- 状态: 任务状态,退出代码,退出信号等。
- 优先级: 相对于其他进程的优先级。
- 程序计数器: 程序中即将被执行的下一条指令的地址。
- 内存指针: 包括程序代码和进程相关数据的指针,还有和其他进程共享的内存块的指针上下文数据: 进程执行时处理器的寄存器中的数据。
- I/O状态信息: 包括显示的I/O请求,分配给进程的I/O设备和被进程使用的文件列表。
- 记账信息: 可能包括处理器时间总和,使用的时钟数总和,时间限制,记账号等。
- 其他信息
3. Linux下的进程
- 描述起来,用结构体(struct)
struct task_struct
{ //进程的所有属性... ...//进程对应的代码和数据的地址... ...//下一个进程的地址struct task_struct* next;
};
在 Linux 系统中,进程控制块(Process Control Block,简称 PCB)通常是用 C 语言中的 struct
结构体来实现的。这个结构体包含了与进程相关的各种信息,比如进程状态、进程 ID、优先级、CPU 寄存器值、内存映射信息等。在 Linux 源代码中,这个描述进程的结构体通常被命名为 task_struct
。
- 课本上称之为PCB(process control block)
- Linux操作系统下的PCB是: task_struct
task_struct 是 PCB 的一种
- 组织起来,用链表或其他高效的数据结构
在 Linux 中,所有进程都通过一个task_list
双向循环链表来连接。每个task_struct
结构体都有一个tasks
成员(通常是list_head
类型),该成员用于将它插入到全局的task_list
链表中。
/** Simple doubly linked list implementation.** Some of the internal functions ("__xxx") are useful when* manipulating whole lists rather than single entries, as* sometimes we already know the next/prev entries and we can* generate better code by using them directly rather than* using the generic single-entry routines.*/struct list_head
{struct list_head *next, *prev;
};
进程=可执行程序 (exe) + task_struct对象(内核对象)
二、进程状态
1. 教科书中的进程状态
在普适的操作系统层面,即站在操作系统学科的角度来说,进程状态可能有如下几种:运行、挂起、阻塞、新建、就绪、等待、挂机、死亡;其中最重要也是最难理解的几种状态分别是:运行、阻塞、挂起。
运行状态
操作系统为了合理分配CPU以及各种硬件资源,也为了更好的调度各个进程,会为CPU创建一个进程队列,为每一个硬件都创建一个等待队列;而让某一个进程处于运行状态本质上就是将该进程对应的PCB放入CPU的运行队列中,然后再将PCB中维护进程状态的变量修改为相应的值,比如0;
因为进程PCB里面有进程的各种属性,以及进程对应的代码和数据的地址,所以CPU从运行队列中取出PCB后,可以根据该PCB来得到进程的各种数据和指令,然后执行相应运算;
所以进程处于运行状态并不一定意味着该进程此刻正在被运行,只要该进程处于CPU的运行队列中即可。所以,运行状态就是进程处于执行中,或者在运行队列中等待执行。(注:CPU是纳秒级的芯片,运算速度非常快,所以只要进程处于CPU的运行队列中,我们就可以认为该进程正在被运行)
阻塞状态
和CPU一样,我们计算机中的各种硬件也是十分有限的,但是需要使用这些硬件资源的进程却有很多,比如很多进程都需要向磁盘中写入数据,又或者要通过网卡发送数据;但是一个磁盘或者一个网卡在同一个时刻只能为一个进程提供服务,那么如果此时有其他运行中的进程需要使用该硬件资源,操作系统就会将该进程的PCB放入硬件的等待队列中,等待硬件来为我提供服务。
上面这种由于访问某种硬件需要进行等待的状态就被称为阻塞状态,阻塞状态本质上就是将进程的PCB从CPU的运行队列中剥离出来,放入硬件的等待队列中,然后将PCB中维护进程状态的变量修改为相应的值,比如1;待该进程获得对应的对应的硬件资源以后,再将该进程放入CPU的运行队列中。
(注:并不是只有等待硬件资源进程才会处于阻塞状态,一个进程等待另一个进程就绪、一个进程等待某种软件资源就绪等都会处于阻塞状态。)
挂起状态
上面我们学习了阻塞状态,处于阻塞状态的进程由于需要等待某种资源,所以它对应的代码和数据在短期内并不会被执行,此时它们仍存在在内存中就相当于浪费了内存资源;而如果当前操作系统处于高IO的情况下,内存空间不足,操作系统就会选择将这些处于阻塞状态的进程对应的代码和数据拷贝一份存放到磁盘中,然后释放内存中那一份,从而节省出内存空间;
上面这种由于内存空间不足,操作系统将在等待资源的进程对应的代码数据放到磁盘中以节省内存空间的状态就被称为挂起状态;挂起状态不会移动进程的PCB,只会移动进程对应的代码和数据。
(注:挂起进程并不是释放进程,因为该进程对应的PCB仍然处于某硬件的等待队列中,当该进程获得对应的资源以后,操作系统仍然可以将该进程对应的代码和数据从磁盘加载到内存中来继续运行,其本质是对内存数据的唤入唤出;同时阻塞不一定挂起,挂起也不一定阻塞,也可能是新建挂起、就绪挂起,甚至是运行挂起。)
[!attention] 阻塞和挂起的区别:
与阻塞(等待)状态不同,在挂起状态下,进程通常不是在等待某种资源或条件的满足,而是被显式地暂停了,可以通过相应的信号(例如,在Linux中的 SIGCONT)来继续执行。
区别:
触发原因:
- 阻塞通常是因为进程在等待某些系统资源或事件。
- 挂起通常是由用户或管理员明确要求的。
可控性:
- 阻塞状态通常是自动的,由系统内核管理。
- 挂起状态通常是可以被用户或管理员控制的。
可中断性:
- 阻塞状态可能是可中断或不可中断的。
- 挂起状态总是可以通过 SIGCONT 信号来解除的。
持续时间:
- 阻塞状态持续到所等待的条件得到满足。
- 挂起状态持续到进程收到一个 SIGCONT 信号。
[!quote] 总结:
进程状态改变的本质是进程对应的 PCB (task_struct 对象) 处于不同设备的运行队列/等待队列中。
2. 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 */
};
R(running)- 运行状态
它表明进程PCB在运行队列里,虽然在运行队列并不意味着进程一定在运行中,但是因为CPU非常快,所以只要进程处于CPU的运行队列中,我们就可以认为该进程正在被运行。
S(sleeping) - 睡眠状态
味着进程在等待事件完成(这里的睡眠有时候也叫做可中断睡眠(interruptible sleep)),Linux下的睡眠状态其实就是我们上面所说的阻塞状态。
注:我们使用 ps axj 指令查看进程状态只能查看进程某一时刻的状态,而外设的速度是要远远低于CPU的,所以我们可以发现,虽然 process 也在执行加法运算,但是我们每次查询时进程基本都处于阻塞状态,因为进程99%的时间都在等待硬件资源就绪,只有1%的时间在进行加法运算以及执行打印代码。
D(disk sleep)- 磁盘休眠状态
有时候也叫不可中断睡眠状态(uninterruptible sleep),在这个状态的进程通常会等待IO的结束。
上面我们提到,当内存空间不足的时候,操作系统会将一部分进程挂起来节省资源;但是如果内存空间严重不足,挂起已经解决不了问题的时候,操作系统就会主动杀掉某些进程;
那么这里就出现了一个问题,万一操作系统把某些非常重要的进程杀掉了怎么办?比如,当前有一个进程需要向磁盘写入一批数据,这批数据是10万名用户一年的转账记录,非常重要;该进程访问磁盘,让磁盘帮它写入数据,在磁盘写数据的时间段内,该进程是属于阻塞状态的,因为它要等待磁盘返回给它一个结果,即是否写入成功;而一旦该进程被操作系统杀掉,且恰好磁盘写入失败了,磁盘将写入结果反馈给该进程发现无人应答,磁盘就只能将该部分数据丢弃然后为其他进程提供服务;此时,这部分十分重要的用户数据就丢了。
为了防止这种情况的发生,Linux设计出了深度睡眠 (D) 状态,处于深度睡眠状态的进程既不能被用户杀掉,也不能被操作系统杀掉,只能通过断电,或者等待进程自己醒来。
注:深度睡眠一般只会在高IO的情况发生下,且如果操作系统中存在多个深度睡眠状态的程序,那么说明该操作系统也即将崩溃了。
T(stopped)- 停止状态
可以通过发送 SIGSTOP 信号给进程来停止(T)进程。这个被暂停的进程可以通过发送 SIGCONT 信号让进程继续运行。
列出kill的选项:
t(tracing stop)- 追踪暂停状态
追踪暂停状态是一种特殊的暂停状态,进程处于此状态表示该进程正在被追踪,比如 gdb 调试进程。
X(dead)- 死亡状态
这个状态只是一个返回状态,死亡状态代表着一个进程结束运行,该进程对应的PCB以及代码和数据全部被操作系统回收,我们不会在任务列表里看到这个状态。
Linux下的进程状态,本质上就是进程PCB中的一个变量:
#define TASK_RUNNING 0
#define TASK_INTERRUPTIBLE 1
#define TASK_UNINTERRUPTIBLE 2
#define __TASK_STOPPED 4
#define __TASK_TRACED 8
/* in tsk->exit_state */
#define EXIT_ZOMBIE 16
#define EXIT_DEAD 32
/* in tsk->state again */
#define TASK_DEAD 64
#define TASK_WAKEKILL 128
因此,进程状态变化的本质:
- 更改PCB中的status变量
- 将 PCB 连入不同的运行队列中
> 两种特殊的进程 <
1. 僵尸进程
什么是僵尸进程
在Linux中,当一个进程完成它的执行但还没有被其父进程清理(也就是读取其退出状态)时,它就会变成僵尸进程。这种情况通常发生在父进程在其子进程结束之前就结束了。在这种情况下,子进程的状态信息会被保留在系统中,以便父进程在以后的某个时候读取。
用代码说明:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>int main()
{int id = fork();if(id > 0){while(1){printf("我是父进程,pid: %d, ppid: %d\n", getpid(), getppid());sleep(1);}}else if(id == 0){while(1){printf("我是子进程,pid: %d, ppid: %d\n", getpid(), getppid());sleep(1);}}else {perror("fork fail");exit(-1);}return 0;
}
kill 掉子进程之后,由于父进程中没有对子进程的退出状态代码进行读取,所以子进程变成了 Z 状态,并且子进程后面还提示了 defunct (失效的,不再使用的),此时,如果父进程一直不对不对子进程进行读取,那么子进程就会变成僵尸进程。
僵尸进程的危害
僵尸进程本身并不占用任何系统资源(如CPU时间或内存),因为它们已经停止执行。然而,每个僵尸进程的PCB还存在于操作系统进程表中,这可能会消耗有限的系统资源。如果有大量的僵尸进程,它们可能会耗尽进程表的空间,导致新的进程无法启动。此外,如果父进程不正确地处理子进程的退出,可能会导致僵尸进程的数量持续增加。
2. 孤儿进程
孤儿进程是指在其父进程执行完成或被终止后仍继续运行的一类进程。这些孤儿进程将被init进程(进程号为1)所收养,并由init进程对它们完成状态收集工作。
[!warning] 两个细节:
父进程退出后并没有变成Z状态:
当一个进程结束时,它的进程描述符会立即消失,而是等待父进程读取其退出状态。在这个等待过程中,进程被称为僵尸进程(Z状态)。如果父进程先于子进程退出,子进程就会被init进程接管,子进程结束后,init进程会负责读取其退出状态,因此,子进程不会变成僵尸进程。子进程被领养后变成了后台进程:
在UNIX系统中,后台进程是指与终端脱离关系,独立运行的进程。当父进程退出,子进程被init进程接管后,子进程就会变成后台进程。这是因为init进程是在系统启动时由内核创建的,它不依赖于任何终端,因此,被它接管的子进程也会变成后台进程。
ps:进程状态后面的 + 号代表着一个进程是前台进程,没有 + 号就代表是后台进程
三、进程的优先级
1. 什么是优先级
优先级和权限不同,权限决定的是一件事情能不能做;优先级是在权限允许的前提下,该事情先做还是后做;
2. 为什么要有优先级
资源是有限的,内存中有很多进程都要占用资源,但是资源是有限的,所以我们需要指定优先级来合理的分配资源;
3. Linux中优先级的特点
Linux 中优先级的表示与维护通过两个变量 PRI (priority) 和 NI (nice) 来完成,每个进程默认的 PRI 都是 80,NI 都是 0;我们可以通过修改 NI 的值来调整进程的优先级,NI 的改动范围为 [-20, 19];PRI 与 NI 的和越小,进程的优先级就越高;
我们也可以通过如下步骤来修改进程优先级 (将进程优先级调高可能需要 sudo 权限):
输入top --> 输入r --> 输入进程id --> 输入NI值
修改进程优先级的本质就是修改进程的nice值
四、进程的其他概念
进程还有一些其他概念:
- 竞争性:系统进程数目众多,而CPU资源只有少量,甚至1个,所以进程之间是具有竞争属性的;(进程为了高效完成任务,更合理竞争相关资源,便具有了优先级)
- 独立性:多进程运行,需要独享各种资源,多进程运行期间互不干扰;(每个进程的PCB以及代码数据都是独立的,一个进程的死亡不会影响其他进程,包括父子进程,子进程崩溃并不会影响父进程)
- 并行:多个进程在多个CPU下分别、同时进行运行,这称之为并行;
- 并发:多个进程在一个CPU下采用进程切换的方式,在一段时间之内,让多个进程都得以推进,称之为并发。(我们用的电脑一般都是并发,只有一个CPU)
相关文章:

【Linux】进程的概念 进程状态 进程优先级
Content 一、什么是进程1. 进程的概念2. 进程的描述 - 进程控制块(PCB)3. Linux下的进程 二、进程状态1. 教科书中的进程状态运行状态阻塞状态挂起状态 2. Linux下的进程状态R(running)- 运行状态S(sleeping) - 睡眠状…...

Go语言热重载和优雅地关闭程序
Go语言热重载和优雅地关闭程序 我们有时会因不同的目的去关闭服务,一种关闭服务是终止操作系统,一种关闭服务是用来更新配置。 我们希望优雅地关闭服务和通过热重载重新加载配置,而这两种方式可以通过信号包来完成。 1、代码实现 package…...

Python实现两个列表相加的方法汇总
1. 使用 “” 运算符 通过 “” 运算符将两个列表相加,得到一个新的列表。例如: list1 [1, 2, 3] list2 [4, 5, 6] result list1 list2 print(result) # [1, 2, 3, 4, 5, 6]2. 使用 extend 方法 使用 extend 方法将一个列表中的元素逐个添加到另…...

debian12.4配置
文章目录 debian12.4配置概述笔记将非root用户添加到sudo组更换国内源配置ssh的客户端访问END debian12.4配置 概述 在虚拟机中装了一个debian12.4, 想配置ssh客户端连接, 出了问题. 配置乱了, 还好长了个心眼, 做了快照. 发现2个问题: debian12.4默认安装完, 有ssh, 先检查…...

linux切换root用户su - root和su root的区别
这里说一下login shell和 no login shell的区别 通过tty客户端登陆的shell就是login shell,通过在图形界面使用ctrlshiftt的方式新建的shell是no login shell login shell 主要读取两个配置文件/etc/profile和~/.bash_profile no login shell 读取的文件和顺序为&am…...

SQL Server Management Studio创建数据表
文章目录 一、建表注意事项1.1 数据类型1.2 建立数据表的基本SQL语法 二、实例说明2.1 创建数据表2.2 实例2 三、标识列和主键示例: 一、建表注意事项 1.1 数据类型 可以看这个去了解数据类型: 1.2 建立数据表的基本SQL语法 建立数据表的基本 SQL 语…...

【AI的未来 - AI Agent系列】【MetaGPT】4.1 细说我在ActionNode实战中踩的那些坑
文章目录 1. MetaGPT 0.5.2 版本的坑1.1 坑一:cannot import name "ActionNode" from "metagpt.actions.action"1.2 坑二:simple_fill 没有参数 schema1.3 坑三:ActionNode一直在循环执行, 2. 升级成 MetaGP…...

Android学习(五):常用控件
Android学习(五):常用控件 常用控件 TextViewEditTextButtonRadioButtonImageView 1、TextView控件 1.1、简介 TextView是用于显示文字(字符串)的控件,可在代码中通过设置属性改变文字的大小、颜色、样式等功能。 1.2、示例…...

基于YOLOv8的学生课堂行为检测,引入BRA注意力和Shape IoU改进提升检测能力
💡💡💡本文摘要:介绍了学生课堂行为检测,并使用YOLOv8进行训练模型,以及引入BRA注意力和最新的Shape IoU提升检测能力 1.SCB介绍 摘要:利用深度学习方法自动检测学生的课堂行为是分析学生课堂表…...

【前后端分离与不分离的区别】
Web 应用的开发主要有两种模式: 前后端不分离 前后端分离 理解它们的区别有助于我们进行对应产品的测试工作。 前后端不分离 在早期,Web 应用开发主要采用前后端不分离的方式,它是以后端直接渲染模板完成响应为主的一种开发模式。以前后端不…...

ubuntu-20.04.6-live-server-amd64安装教程-完整版
简介 Ubuntu 20.04.6 Live Server AMD64 安装教程 - 完整版" 提供了详细的指南,旨在帮助用户在使用 AMD64 架构的服务器上安装 Ubuntu 20.04.6 Live Server 版本。该教程包含全面的步骤和详细说明,使用户能够顺利完成整个安装过程,建立…...

C for Graphic:Sliced Circle Image
不做UI不知道,没想到时至今日,ugui居然没有sliced filled image模式,用circle做filled,不能用sliced九宫格图,导致每次使用这个效果必须一张新图,何其浪费资源。 原始功能如下: 我…...

入门级的 DataV 教程,适用于 Vue 2
入门级的 DataV 教程,适用于 Vue 2。这个教程将指导您创建一个名为 datav-project 的 Vue 项目,并展示如何在其中使用 DataV。我们将从安装 Vue CLI 开始,然后创建项目,接着添加 DataV,并最后显示一个简单的数据可视化…...

JVM工作原理与实战(二十一):内存管理
专栏导航 JVM工作原理与实战 RabbitMQ入门指南 从零开始了解大数据 目录 专栏导航 前言 一、不同语言的内存管理 1.C/C的内存管理 2.Java的内存管理 二、垃圾回收的对比 1.自动垃圾回收与手动垃圾回收的对比 2.优点与缺点 总结 前言 JVM作为Java程序的运行环境&#…...

Win10 打开文件突然鼠标变成一个蓝色大圈卡住点不了也打不开文件,重启电脑也是这样
环境: Win10 专业版 加密客户端环境 问题描述: Win10 打开桌面word文件突然鼠标变成一个蓝色大圈卡住点不了也打不开文件,重启电脑也是这样,只有蓝色圈变大没有鼠标指针出现圈卡着不会动,和那些有鼠标箭头加小蓝色圈不一样 解决方案: 某网上查看的,还是要自己排查…...

论文阅读笔记AI篇 —— Transformer模型理论+实战 (四)
论文阅读笔记AI篇 —— Transformer模型理论实战 (四) 一、理论1.1 理论研读1.2 什么是AI Agent? 二、实战2.1 先导知识2.1.1 tensor的创建与使用2.1.2 PyTorch的模块2.1.2.1 torch.nn.Module类的继承与使用2.1.2.2 torch.nn.Linear类 2.2 Transformer代…...

Template -- Vue2
Vue2 版本 Node 14.14.0Npm 6.14.8Vue vue/cli 5.0.3 npm install -g vue/cli5.0.3 cnpm cnpm7.1.0 npm install -g cnpm7.1.0 --registryhttps://registry.npm.taobao.org 项目 创建 vue create single # vue 2.6.14配置 // vue.config.js const { defineConfi…...

zookeeper window 安装
下载 Apache ZooKeeper 解压Zookeeper安装包到指定目录,注意目录不要有空格。 备份zoo_sample.cfg并改名zoo.cfg 注意:此处的路径一定要使用双斜杠" \\ " D:\\apache-zookeeper-3.8.3-bin\\data 新建环境变量:ZOOKEEPER_HOME D…...

Redis 面试题 | 02.精选Redis高频面试题
🤍 前端开发工程师、技术日更博主、已过CET6 🍨 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 🕠 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 🍚 蓝桥云课签约作者、上架课程《Vue.js 和 E…...

大数据开发之kafka(完整版)
第 1 章:Kafka概述 1.1 定义 Kafka是一个分布式的基于发布/订阅模式的消息队列,主要应用于大数据实时处理领域。 发布/订阅:消息的发布者不会将消息直接发送给特定的订阅者,而是将发布的消息分为不同的类别,订阅者只…...

单体架构、微服务和无服务器架构
前言 在这篇文章中,我将演示在决定使用单体架构、微服务架构和无服务器架构时的权衡的简化心智模型。目标是突显每种风格的固有优势和缺陷,并提供关于何时选择哪种架构风格的指导。 单体架构 对于小团队或项目来说是理想的入门架构。它简单易上手&…...

Github仓库使用方式
主要参考: 「详细教程」使用git将本地项目上传至Github仓库(MacOS为例)_github上传代码到仓库-CSDN博客 新建文件夹参考: GitHub使用指南——建立仓库、建立文件夹、上传图片详细教程-CSDN博客 一、新建一个 github 仓库&#…...

Harmony Ble蓝牙App(四)描述符
Harmony Ble蓝牙App(四)描述符 前言正文一、优化二、描述① 概念② 描述提供者③ 显示描述符 三、源码 前言 上一篇中了解了特性和属性,同时显示设备蓝牙服务下的特性和属性,本文中就需要来使用这些特性和属性来完成一些功能。 正…...

C# 实现单线程异步互斥锁
文章目录 前言一、异步互斥锁的作用是什么?示例一、创建和销毁 二、如何实现?1、标识(1)标识是否锁住(2)加锁(3)解锁 2、异步通知(1)创建对象(2&a…...

Java设计模式中策略模式可以解决许多if-else的代码结构吗? 是否能满足开闭原则?
Java设计模式中策略模式可以解决许多if-else的代码结构吗? 是否能满足开闭原则? 是的,策略模式可以帮助解决许多if-else的代码结构。通过将不同的算法封装成不同的策略类,然后在需要的时候动态地切换策略,可以避免使…...

[C#]C# winform部署yolov8目标检测的openvino模型
【官方框架地址】 https://github.com/ultralytics/ultralytics 【openvino介绍】 OpenVINO(Open Visual Inference & Neural Network Optimization)是由Intel推出的,用于加速深度学习模型推理的工具套件。它旨在提高计算机视觉和深度学…...

力扣刷MySQL-第五弹(详细讲解)
🎉欢迎您来到我的MySQL基础复习专栏 ☆* o(≧▽≦)o *☆哈喽~我是小小恶斯法克🍹 ✨博客主页:小小恶斯法克的博客 🎈该系列文章专栏:力扣刷题讲解-MySQL 🍹文章作者技术和水平很有限,如果文中出…...

用C语言实现简单的三子棋游戏
目录 1 -> 模块简介 2 -> test.c 3 -> game.c 4 -> game.h 1 -> 模块简介 test.c:测试游戏逻辑 game.c: 函数的实现 game.h:函数的声明 2 -> test.c #define _CRT_SECURE_NO_WARNINGS 1#include "game.h";void menu() {printf("****…...

Yaklang 中的类型和变量
Yaklang 的类型其实非常简单,我们仅需要记住如下类型即可 string 字符串类型,用以快速构建一个字符串int 整数类型:在 64 位机中,int 和 int64 是一样的float 浮点类型,用来定义和表示浮点数byte 本质上等同于 uint8u…...

C语言从入门到实战——编译和链接
编译和链接 前言一、 翻译环境和运行环境二、 翻译环境2.1 预处理(预编译)2.2 编译2.2.1 词法分析2.2.2 语法分析2.2.3 语义分析 2.3 汇编2.4 链接 三、 运行环境 前言 在C语言中,编译和链接是将源代码转换为可执行文件的两个主要步骤。 编…...