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

武汉网站seo推广公司/google官网

武汉网站seo推广公司,google官网,原始传奇官网登录入口,网站建设整改落实情况驱动的分离与分层思想 分离:硬件信息分离; 在编写硬件驱动的时候,需要操作许多硬件寄存器。比如gpio 驱动,你需要知道gpio控制器 寄存器的地址,你想要哪个gpio输出?或是输入? 这些操作最终都是靠设置寄存…

驱动的分离与分层思想

分离:硬件信息分离;
在编写硬件驱动的时候,需要操作许多硬件寄存器。比如gpio 驱动,你需要知道gpio控制器 寄存器的地址,你想要哪个gpio输出?或是输入? 这些操作最终都是靠设置寄存器完成,如果你想要操作的gpio变了、方向变了,这些硬件信息的都要修改驱动。

或者说同一个系列的soc 它们的寄存器地址不同、soc 更新换代寄存器地址改变等等,但是寄存器的设置方法相同,驱动无法兼容多个硬件。
这样,明明可以只用一份代码通,却因为硬件不同要写无数份,代码重用性很低,内核中也会多许多这种垃圾代码。
这种要不断修改、重用性低的驱动是不理想的,有没有可能做出一份通用且不需要经常修改代码的驱动呢?

可以,硬件信息分离。把控制器的寄存器地址、要输出的引脚、方向等信息从驱动分离出来另外保存,原本的驱动就变成一些纯软件代码与操作寄存器的代码,这样就不需要因为硬件的改变而不断修改代码。

分离的思想就是把硬件信息从驱动中分离出来,做出一套通用的驱动。

Linux 驱动如何实现分离:内核3.x 以前使用 .c(结构体) 文件描写硬件信息,有设备树后用设备描写硬件信息。

分层:代码分层。
使用过内核通用的gpio驱动可以知道,内核gpio驱动分为两部分:

  1. gpio核心层 (与硬件无关的软件层,负责管理下层的各种驱动,调用它们提供的硬件操作函数(下层一般会把操作函数设成回调函数)进行封装,实现各个厂家的驱动统一的操作方法)
  2. chip_xxx_gpio.c 某个soc 厂家为自己芯片编写的gpio硬件驱动。(实现gpio功能,各个厂家的操作方式可能不同,所以操作函数也不同)

为什么要分层呢?
因为linux内核是要兼容多个平台的,不同的平台可能寄存器的设计不同导致方法不同,那又会衍生出很多驱动。
所以内核提出了分层思想,由与硬件无关的软件层作为上层(核心层)来管理下层驱动,而各个厂家则根据自己的硬件编写驱动代码作为下层(硬件驱动层)(不管你硬件怎么变,暴露给上层的接口必须一致,按照上层的管理方法来编写)。

加上硬件信息,一个驱动一共就是三部分:通用的驱动框架、硬件驱动和硬件信息(硬件信息+硬件驱动=硬件驱动层)。
在这里插入图片描述

Linux 驱动-总线-设备 模型

分离是把硬件信息和驱动代码分离开来,那么在Linux内核中如何实现分离。
Linux 内核建立了设备-总线-驱动 这样的模型,用struct device 来表示设备,用struct device_driver 来表示驱动。(它们都定义于include\linux\device.h)
(struct device 和struct device_driver 只是两个基类,根据不同的总线会衍生出很多派生类,比如platform_device(它可以描述设备信息)、platform_driver (可以描述驱动))

struct device {struct device		*parent;				//父设备struct device_private	*p;					struct kobject kobj;const char		*init_name; /* initial name of the device */	//名字const struct device_type *type;struct mutex		mutex;	/* mutex to synchronize calls to* its driver.*/struct bus_type	*bus;		/* type of bus device is on */		//总线类型struct device_driver *driver;	/* which driver has allocated thisdevice */void		*platform_data;	/* Platform specific data, device	//platform 数据core doesn't touch it */void		*driver_data;	/* Driver data, set and get with	//驱动数据,一般可以在驱动代码中设置为比较常用的结构体变量dev_set/get_drvdata */struct dev_pm_info	power;struct dev_pm_domain	*pm_domain;#ifdef CONFIG_PINCTRLstruct dev_pin_info	*pins;
#endif#ifdef CONFIG_NUMAint		numa_node;	/* NUMA node this device is close to */
#endifu64		*dma_mask;	/* dma mask (if dma'able device) */u64		coherent_dma_mask;/* Like dma_mask, but foralloc_coherent mappings asnot all hardware supports64 bit addresses for consistentallocations such descriptors. */unsigned long	dma_pfn_offset;struct device_dma_parameters *dma_parms;struct list_head	dma_pools;	/* dma pools (if dma'ble) */struct dma_coherent_mem	*dma_mem; /* internal for coherent memoverride */
#ifdef CONFIG_DMA_CMAstruct cma *cma_area;		/* contiguous memory area for dmaallocations */
#endif/* arch specific additions */struct dev_archdata	archdata;struct device_node	*of_node; /* associated device tree node */		//设备树节点struct fwnode_handle	*fwnode; /* firmware device node */dev_t			devt;	/* dev_t, creates the sysfs "dev" */		//设备号u32			id;	/* device instance */spinlock_t		devres_lock;struct list_head	devres_head;struct klist_node	knode_class;struct class		*class;											//device 所属的类const struct attribute_group **groups;	/* optional groups */		//属性文件,组void	(*release)(struct device *dev);								//用于释放device 的回调函数struct iommu_group	*iommu_group;bool			offline_disabled:1;bool			offline:1;
};
struct device_driver {const char		*name;				//驱动名字struct bus_type		*bus;			//总线类型struct module		*owner;			//一般设置为THIS_MODULESconst char		*mod_name;	/* used for built-in modules */bool suppress_bind_attrs;	/* disables bind/unbind via sysfs */const struct of_device_id	*of_match_table;		//用于设备树匹配的id	const struct acpi_device_id	*acpi_match_table;int (*probe) (struct device *dev);		//当匹配成功后会调用probe(在probe中我们可以自由发挥,做任何想做的事,比如硬件的设置)int (*remove) (struct device *dev);					//一方想要卸载时会调用remove(匹配成功的状态下)void (*shutdown) (struct device *dev);int (*suspend) (struct device *dev, pm_message_t state);int (*resume) (struct device *dev);const struct attribute_group **groups;				//属性文件,组const struct dev_pm_ops *pm;struct driver_private *p;
};

现在有了设备信息、驱动代码,但是要把它们合在一起使用才能算是完整可用的驱动代码,内核里有那么多个驱动,就会产生无数个device 和device_driver,如何把它们匹配在一起?
这时候总线就出来了,它能把相互对应的device 和device_driver 匹配起来形成完整的驱动。(此总线并非硬件总线,而是Linux内核中虚拟出来的,用来匹配设备信息和驱动代码)
总线用一个struct bus_type 类型的数据结构来描述:

include\linux\device.h
struct bus_type {const char		*name;				//总线名const char		*dev_name;struct device		*dev_root;struct device_attribute	*dev_attrs;	/* use dev_groups instead */const struct attribute_group **bus_groups;const struct attribute_group **dev_groups;const struct attribute_group **drv_groups;int (*match)(struct device *dev, struct device_driver *drv);		//负责判断设备与驱动之间是否匹配的函数,至关重要!!!int (*uevent)(struct device *dev, struct kobj_uevent_env *env);int (*probe)(struct device *dev);int (*remove)(struct device *dev);void (*shutdown)(struct device *dev);int (*online)(struct device *dev);int (*offline)(struct device *dev);int (*suspend)(struct device *dev, pm_message_t state);int (*resume)(struct device *dev);const struct dev_pm_ops *pm;const struct iommu_ops *iommu_ops;struct subsys_private *p;struct lock_class_key lock_key;
};

在这里插入图片描述
查看device 与 device_driver 匹配过程:
原理分析:
注册device 时会将它添加到bus->p->klist_devices链表,然后获取bus->p->klist_drivers 链表,将device 与链表中的所有device_driver 一一比较,如果匹配成功就会调用device_driver->probe。
同样注册注册device_driver 时也会将它添加到bus->p->klist_drivers链表,然后获取bus->p->klist_devices 链表,将device_driver 与链表中的所有device 一一比较,如果匹配成功就会调用device_driver->probe。

struct device 使用device_register() 向内核注册,device_driver 使用driver_register() 向内核注册。

device_register

在这里插入图片描述
device_add
->bus_add_device
bus_add_device 中将dev->p->knode_bus(struct klist_node) 添加到bus->p->klist_devices(struct klist) 链表中 (bus根据设备所属的总线来定,可能是platform、i2c、spi… 任何总线)。
在这里插入图片描述
device_add
->bus_probe_device
->device_attach (attach 表示附加的意思,此函数将device 附加到某个device_driver 上)
device_attach 中调用bus_for_each_drv 遍历bus 下的所有device_driver。
在这里插入图片描述
klist_iter_init_node 初始化了一个klist_iter (i)
i->i_klist = k; //被设置为了bus->p->klist_drivers(它就是device_driver 的klist 链表)
i->i_cur = n; //i_cur 是struct klist_node 类型的(传入的start为NULL,所以i_cur == NULL)
循环的调用next_driver(&i) 来遍历bus->p->klist_drivers 所有节点,获取与节点对应的device_driver
(依靠刚刚构建的klist_iter 来找到下一个链表节点,由于klist_iter->i_cur 为空,所以可能是从头开始获取节点之类的)

拿到了device_driver,就可以与新注册device 进行比对了,调用fn 也就是传入的_device_attach 进行比较,如果匹配上就会绑定device 和device_driver(device->driver = driver),并且调用device_driver->probe。
在这里插入图片描述
在这里插入图片描述
device_add
->bus_probe_device
->device_attach
->bus_for_each_drv
->__device_attach //判断device 与device_driver 是否匹配
在这里插入图片描述
比较的方法由具体的总线提供,直接调用device_driver->bus->match 回调函数。
在这里插入图片描述
假如总线是platform 的话,那么bus->match 就是platform_match。
在这里插入图片描述
platform_match 中有三种匹配方式,在有设备树的时我们一般使用设备树的匹配方式(比较compatible 的值),没有设备树则使用方法3 和4。
在这里插入图片描述
of_driver_match_device 是通过platform_driver->driver->of_match_table->compatible 与platform_device->device->of_node 中读取compatible 属性值来比较。
of_driver_match_device
->of_match_device
在这里插入图片描述
platform_match_id 是通过比较platform_device 的名字和platform_driver->id_table->name 来判断是否匹配。
在这里插入图片描述

如果匹配则调用 driver_probe_device 绑定device 与device_driver 的关系,并且调用bus->probe 或device_driver->probe
driver_probe_device
->really_probe
在这里插入图片描述
优先调用device->bus->probe,如果没提供则调用deivce_driver->probe
在这里插入图片描述

driver_register

driver_register 调用bus_add_driver 向总线添加device_driver
在这里插入图片描述
bus_add_driver 将device_driver->p->knode_bus (klist_node)节点添加到bus->p->klist_drivers (klist)链表。
然后调用driver_attach,将新注册的device_driver 与bus 下的所有device 进行比对。
在这里插入图片描述
driver_attach 调用bus_for_each_dev 遍历总线下的所有device,调用_driver_attach 将新注册的device_driver 与device 一一比对。
在这里插入图片描述
bus_for_each_dev 循环遍历bus 下的所有device,调用__driver_attach 进行device 与device_driver比较
在这里插入图片描述
__driver_attach 调用driver_match_device 来判断device 和device_driver 是否匹配(这一步和__device_attach 中是一样的调用bus->match 来对比)
如果两者匹配的话调用driver_probe_device->really_probe 绑定device 和device_driver的关系,然后调用bus->probe 或device_driver->probe (这一步和__device_attach 中也是一模一样的)
在这里插入图片描述

根据不同外设的特点,内核定义了多条常用的总线,比如platform总线、i2c 总线、spi总线… 等等。
定义如下:
//drivers/base/platform.c
在这里插入图片描述
//drivers/i2c/i2c-core.c
在这里插入图片描述
//driver/spi/spi.c
在这里插入图片描述
可以在命令行查看内核具体定义了哪些总线,如:
在这里插入图片描述
为什么要定义这么多总线类型,以i2c 和platform 来举例:
i2c 总线:
挂在i2c总线(硬件)下的从设备,比如加密芯片、rtc芯片、触摸屏芯片等等,这些从设备它们也需要驱动,它们自然也要按照分离思想来设计。
那么内核中的i2c 总线就是用来帮助i2c从设备的设备信息 和驱动,互相匹配的。

platform 总线:
像i2c、spi这样硬件有实体总线的,从设备驱动可以用总线来管理。
那么没有总线的硬件外设怎么办,比如gpio、uart、i2c控制器、spi 控制器…等等,这些通通用platform 总线来管理。

如何注册一个总线(常用的总线内核中已经注册好了,通常情况下无需自己创建一条总线):
可以用bus_register 函数注册一条总线:
int bus_register(struct bus_type *bus)
bus_unregister 注销一条总线:
void bus_unregister(struct bus_type *bus)
如platform 总线的注册代码如下:
//drivers\base\platform.c
在这里插入图片描述

platform 总线

根据platform 总线和外设的特点,为了更好的描述设备信息和驱动代码,在devicedevice_driver 基础上衍生了platform_deviceplatform_driver 两个派生类。

//include/linux/platform_device.h
struct platform_device {const char	*name;					//设备名int		id;bool		id_auto;struct device	dev;				//派生类仍然包含基础的device,因为里面有不可或缺的重要信息u32		num_resources;				//资源数量struct resource	*resource;			//描述硬件设备的资源,资源包括寄存器地址范围、irq 等等。const struct platform_device_id	*id_entry;		//用于匹配的idchar *driver_override; /* Driver name to force a match *//* MFD cell pointer */struct mfd_cell *mfd_cell;/* arch specific additions */struct pdev_archdata	archdata;
};

在kernel v3.x 版本以上,内核引入设备树,所以硬件信息往往在设备树中描述。内核代码会解析设备树,把它转化为一个platform_device。
例如这是一个描述gpio控制器的设备树节点:
reg 第一个字段表示gpio控制器寄存器的起始地址,第二个字段表示长度。(物理地址)
interrupts 表示中断号。(共享中断 中断号 中断触发类型)
在这里插入图片描述

//include/linux/platform_device.h
struct platform_driver {//当platform_driver与platform_device 匹配时就会调用probe(在probe函数中可以自由发挥,写任何东西,比如驱动代码)int (*probe)(struct platform_device *);	//当platform_driver 或是platform_device 一方卸载时就会调用remove (匹配完成的情况下)//(在remove中通常做与probe 相反的操作,比如probe 中申请了内存,那么remove 就要释放内存)int (*remove)(struct platform_device *);	void (*shutdown)(struct platform_device *);int (*suspend)(struct platform_device *, pm_message_t state);int (*resume)(struct platform_device *);struct device_driver driver;				//派生类任然包含基类,这是很重要的(device_driver 中包含决定双方是否匹配的重要信息)const struct platform_device_id *id_table;	//用于匹配的idbool prevent_deferred_probe;
};

在platform_device 中有一个resource 成员,它对于描述硬件信息是非常重要的。
它用来描述一个资源,资源包括寄存器地址、中断等等。(可描述的资源很多,参考宏定义)

//include/linux/ioport.h
/*
如果所描述的资源是寄存器地址(IORESOURCE_MEM 类型),那么:
start 保存着reg 的起始地址,end 保存着reg的末尾地址。start-end 就描述出了一段地址范围。
如果描述的是irq,那么:start 保存着irq 的值。
*/
struct resource {resource_size_t start;resource_size_t end;const char *name;			//资源的名字unsigned long flags;struct resource *parent, *sibling, *child;
};//include/linux/ioport.h
#define IORESOURCE_TYPE_BITS	0x00001f00	/* Resource type */
#define IORESOURCE_IO		0x00000100	/* PCI/ISA I/O ports */		//io内存地址资源类型
#define IORESOURCE_MEM		0x00000200								//mem内存地址资源类型
#define IORESOURCE_REG		0x00000300	/* Register offsets */
#define IORESOURCE_IRQ		0x00000400								//irq 资源类型
#define IORESOURCE_DMA		0x00000800
#define IORESOURCE_BUS		0x00001000
......

那么platform_deviceplatform_driver 这两个结构体究竟该如何使用它呢,以imx6ull 的gpio驱动为例:
首先硬件信息会用设备树节点描述,由内核解析成一个platform_device 注册到内核中。
(没有设备树的版本,驱动需要自己创建一个platform_device 结构体,设置里面的内容,然后向内核注册。使用platform_device_register 函数注册)
int platform_device_register(struct platform_device *);
在这里插入图片描述
在驱动中,需要构建一个platform_driver,初始化内容,并调用platform_driver_register 向内核注册。
在这里插入图片描述
细看platform_driver 中设置的内容:
device_driver->name :是驱动的名字,它也可以用来判断platform_device 与platform_driver 是否匹配。(非设备树情况下)
device_driver->of_match_table :设备树特有的匹配方式。在dtb节点 和of_match_table 中都有一个compatible 属性,它用来判断驱动与设备是否兼容,如果compatible的值是相同的那么就就判断他两是匹配的。data 是与硬件平台相关的数据。
在这里插入图片描述
在这里插入图片描述
id_table:不使用设备树情况下的一种匹配方式,通过对比id_table->name 与platform_device->name 来判断两者是否兼容。
在这里插入图片描述
probe:当匹配完成之后,就会自动调用probe 函数了,在probe函数中我们可以做任何事情,比如硬件的设置等等。
参考mxc_gpio_probe 来看看它做了什么:
(传入的参数就是由设备树节点转化而来的platform_device)
在这里插入图片描述
除了这些,在probe 中还可以做任何事:注册irq、设置driver_data 等等。
这个函数可以设置platform_device->dev.drver_data,可以把它设置成任何驱动中常用的变量地址。
在这里插入图片描述
platform_device->dev.of_node 指向的就是与驱动所匹配的设备树节点,可以用它来获取设备树节点。

platform_driver 与platform_device 注册流程

总结前面的内容:为了实现硬件信息的分离,Linux 内核用一个platform_device 来描述硬件信息,用platform_driver 来描述驱动代码;由platform 总线来管理,帮助它们相互匹配。
使用platform总线管理的设备都要调用platform_device_register 注册platform_device,驱动要调用platform_driver_regster 注册platform_driver。每当platform_device 和platform_driver 匹配就会调用platform_driver.probe 来执行驱动代码。
#define platform_driver_register(drv) \ __platform_driver_register(drv, THIS_MODULE) extern int __platform_driver_register(struct platform_driver *, struct module *);

int platform_device_register(struct platform_device *);

那么双方究竟是如何完成匹配的,又是如何调用到probe 函数的?这就要看看platform_device_registerplatform_driver_regster 是如何注册的。

代码解析
调用platform_device_register 注册platform_device

platform_device_register->platform_device_add

将platform_device->dev 的父设备设为platform_bus (在注册platform 总线时创建的)
platform_device->dev.bus 设为platform_bus_type。
在这里插入图片描述
调用device_add 添加platform_device->dev (struct device)。
在这里插入图片描述
(从device_add 开始就是device 的注册过程,参考前面的device与device_driver 匹配过程)

调用platform_driver_register 注册platform_driver

#define platform_driver_register(drv) \__platform_driver_register(drv, THIS_MODULE)

__platform_driver_register 中将platform_driver->driver.probe 设置为platform_drv_probe 那么在device 和device_driver 匹配成功后就会调用platform_drv_probe 。
调用driver_register 注册platform_driver->driver (参考前面的的device_driver 注册过程,device 与device_driver 匹配过程)
在这里插入图片描述
在device 与device_driver 匹配成功后,最终将调用device_driver->probe 对于platfrom 总线来说,它就是platform_drv_probe。
在platform_drv_probe 中会调用platform_driver->probe(也就是各自驱动中实现的真正的驱动代码了)
在这里插入图片描述

相关文章:

platform 总线

驱动的分离与分层思想 分离:硬件信息分离; 在编写硬件驱动的时候,需要操作许多硬件寄存器。比如gpio 驱动,你需要知道gpio控制器 寄存器的地址,你想要哪个gpio输出?或是输入? 这些操作最终都是靠设置寄存…...

2023第10届生物发酵展3月30-4月1号山东济南开展,参观路线来了

2023第10届生物发酵展3月30-4月1号山东济南开展,参观路线来了!展会时间:2023年3月30日-4月1日展馆地址:山东国际会展中心(济南市槐荫区日照路1号)展馆:4号馆、5号馆BIO CHINA生物发酵展&#xf…...

RK356x U-Boot研究所(命令篇)3.6 fdt命令的用法

平台U-Boot 版本Linux SDK 版本RK356x2017.09v1.2.3文章目录 一、fdt命令的配置二、fdt命令的定义三、fdt命令的用法3.1 fdt list3.2 fdt rm3.3 fdt set一、fdt命令的配置 .config配置文件需要有以下配置: rk3568_defconfig默认已使能。 二、fdt命令的定义 usb命令定义在cm…...

2023年社工工资多少钱一月 能领多少补贴

2023年社会工作者人员的待遇还算可以,每月的全额工资一共5000多,扣完五险一金以后每月的到手工资一共4000多,不同地区薪资也是不同的,一线城市会在7千元以上,还可以领取几百到几千元不等的补贴。 12023年社工工资多少钱…...

面试攻略,Java 基础面试 100 问(十一)

抽象类(abstract class)和接口(interface)有什么异同? 抽象类和接口都不能够实例化,但可以定义抽象类和接口类型的引用。一个类如果继承了某个抽象类或者实现了某个接口都需要对其中的抽象方法全部进行实现&#xff…...

接口测试(Fiddler工具)

目录 1.Fiddler是什么? 2.Fiddler的原理 3.Fiddler安装 4.Fiddler界面 4.1.常用工具 4.2 会话列表 4.3 状态栏 4.4 内容显示区 1.Fiddler是什么? Fiddler是客户端与服务器之间的HTTP代理,是当前最常用的HTTP协议抓包工具。 主要功能&a…...

Debian/Ubuntu 安装和使用 perf 调试工具

为操作系统安装基本依赖环境:apt-get update -y apt-get upgrade -y apt-get install lrzsz zip unzip libkrb5-dev libicu-dev screen iftop openssl libssl-dev libunwind8 iftop net-tools gcc gdb cmake curl wget -y apt-get install gcc gdb cmake python-dev…...

【Python语言基础】——Python NumPy 数组连接

Python语言基础——Python NumPy 数组连接 文章目录 Python语言基础——Python NumPy 数组连接一、Python NumPy 数组连接一、Python NumPy 数组连接 连接 NumPy 数组 连接意味着将两个或多个数组的内容放在单个数组中。 在 SQL 中,我们基于键来连接表,而在 NumPy 中,我们按…...

解决IDEA报错:无效的目标发行版: 17

解决IDEA报错:无效的目标发行版: 17 目录解决IDEA报错:无效的目标发行版: 17报错由来解决报错【1】检查setting设置,查看编译器编译模块的编译版本是否是你需要的【2】尝试去修改当前项目的启动设置,设置JRE为你需要的版本。【3】…...

Redis第四讲

目录 四、Redis04 4.1 Redis集群应用场景 4.2 集群 4.2.1 基本原理 4.2.2 主从复制的作用 4.3 配置集群(一台虚拟机) 4.3.1 规划网络 4.3.2 创建节点 4.3.3 创建目录 4.3.4 配置redis7001.conf 4.3.5 配置其余文件 4.3.6 后台启动redis 4.3…...

Linux Ubuntu 软件安装与卸载

文章目录1 下载 deb 安装包后安装2 清理安装包3 卸载安装2 Ubuntu升级某个软件参考:1 下载 deb 安装包后安装 进入下载位置,执行 terminal sudo dpkg -i *.deb推荐sudo apt install *.deb 2 清理安装包 sudo apt-get install 会将下载的文件放在 /var…...

metasploit穷举模块

目录 工具介绍 常用模块 参数介绍 工具使用 工具介绍 Metasploit框架(Metasploit Framework, MSF)是一个开源工具, 旨在方便渗透测试,它是由Ruby程序语言编写的模板化框架,具有很好的扩展性,便于渗透测试人员开发、使用定制的…...

day35 贪心算法 | 435、无重叠区间 763、划分字母区间 56、合并区间

题目 435、无重叠区间 给定一个区间的集合,找到需要移除区间的最小数量,使剩余区间互不重叠。 注意: 可以认为区间的终点总是大于它的起点。 区间 [1,2] 和 [2,3] 的边界相互“接触”,但没有相互重叠。 示例 1: 输入: [ [1,2], [2,3], […...

C++Primer15.5节练习

练习15.18: Base* p &d1:合法 p &d2:不合法,只有当派生类公有地继承基类时,用户代码才能使用派生类向基类的转换 p &d3:不合法,只有当派生类公有地继承基类时&#xff0…...

【日常点滴019】Python制作流浪气球游戏(导弹射击类)

Python制作流浪气球游戏(导弹射击类)教学课程代码(分步教学版)1、构建全局通用代码结构2、构建气球精灵类3、构建导弹精灵类4、碰撞检测5、构建游戏信息类 (最终完整代码)教学课程代码(分步教学…...

effective c++阅读之旅---条款29

为"异常安全"而努力是值得的! 什么是异常安全? 所谓的"异常安全",往往值得是函数接口的异常安全,它要求函数满足两个条件: 异常抛出时: 1、不泄露任何资源 2、不允许数据被破坏 异常安…...

Android system — 进程生命周期与ADJ

Android system — 进程oom_adj0. 引言1. 进程的生命周期1.1 Foreground process1.2 Visible process1.3 Service process1.4 Background process1.5 Empty process2. Lowmemorykiller2.1 ADJ级别2.2 进程state级别2.3 lmk策略2.4 如何查看应用oom_adj值3. 注意0. 引言 本文主要…...

vue3+ts+node个人博客系统(三)

一.主页顶部和中心面板布局 (1) 首先先去element-plus选择合适的布局el-container (2)在头部处编写相应的菜单栏el-menu,在这里要注意动态绑定路由的问题:default-active"$route.path"。将default-active设置为$route.path,el-me…...

Python第三方模块

♥️作者:小刘在C站 ♥️个人主页:小刘主页 ♥️每天分享云计算网络运维课堂笔记,努力不一定有收获,但一定会有收获加油!一起努力,共赴美好人生! ♥️夕阳下,是最美的绽放&#xff0…...

怎样查询PMP成绩?

【如何查询成绩】1、输入网址(PMI官网,不知道网址的私戳),点击 Log In如果忘记 PMI 的账号和密码了,怎么办?可以在你报名机构官网的个人中心的学习中心的我的报名处查看 PMI 的注册名和密码2、点击 Exam An…...

说说变量 __name__ 和它可能取到的一个值 __main__

结合 例子 弄懂 变量__name__ 和它的值’ main’这两个东西。 首先,明白两个定义, __name__是一个变量, __main__是个普通字符串,不是变量,但可以作为变量的值。 例子: 1.py 代码如下: if _…...

软考高级-信息系统管理师之整体管理(最新版)

整体管理 1、项目整体管理概述2、制定项目章程(选择,案例,论文)制定项目章程过程制定项目章程的依据1、协议2.项目工作说明书:3、商业论证4、事业环境因素包括,但不限于如下事项。5、组织过程资产:项目选择方法项目启动会议项目目标引导技术3、制订项目管理计划(选择)项目管…...

JVM学习篇垃圾收集器ParNewCMS与底层三色标记算法详解

1. 垃圾收集算法 2. 分代收集理论 当前虚拟机的垃圾收集都采用分代收集算法,这种算法没有什么新的思想,只是根据对象存活周期的不同将内存分为几块。一般将java堆分为新生代和老年代,这样我们就可以根据各个年代的特点选择合适的垃圾收集算法…...

基于FFmpeg和Screen Capturer Recorder实现屏幕和声音的录制

当我们看到一些精彩的视频画面,但无法下载时,可以通过录屏的方式将视频和音频录制下来。 这个时候我们需要安装采集视频和音频的工具screen-capture-recorder。 以下是在windows10环境下,基于FFmpeg和Screen Capturer Recorder实现屏幕和声音…...

猿人学14题详解

目测重点在于cookie:mz和m 获取mz.js: https://match.yuanrenxue.com/static/match/match14/m.js 获取设置m: https://match.yuanrenxue.com/api/match/14/m 一、还原16进制 const fs require(fs); const parser require(babel/parser); const gen…...

Allegro如何快速把推挤的走线变平滑操作指导

Allegro如何快速把推挤的走线变平滑操作指导 Allegro有个非常强大的功能,推挤命令,可以快速的让走线以不报DRC的形式避让目标 推挤后的效果如下图 但是走线不够平滑,如果每一段都去再推一下比较费时间,下面介绍allegro本身自带的优化类似走线的功能 具体操作如下 点击Rout…...

nginx基础学习

作为前端开发者,也很有必要了解一些运维部署知识。 nginx的作用有哪些? 负载平衡动静分离反向代理 何为反向代理? 反向代理即是,用户访问nginx服务器,nginx又将请求转发到真正服务器上,为什么用户不能直…...

【HDFS】FsDatasetImpl#recoverClose方法

recoverClose的目的recoverClose的过程recoverClose的调用点一、前言 HDFS客户端写文件时,如果某个datanode发生错误或者异常。客户端会把这个datanode从pipeline里踢除,然后进行pipiline recovery,用剩余datanodes去写或者满足一定的条件时补充新的datanode到pipeline中写…...

加油站会员管理小程序实战开发教程15 完结篇

这篇是本次实战课程的最后一篇,我们在上篇还有两个问题没解决。一个是会员卡类型显示不对,一个是不同的会员卡我们希望背景色显示不同。我们先处理一下这两个问题 1 显示会员卡类型 在列表上直接显示会员卡类型,目前显示的是数字,这个是因为枚举类型导致的。枚举类型在数…...

学习 Python 之 Pygame 开发坦克大战(五)

学习 Python 之 Pygame 开发坦克大战(五)坦克大战完善地图1. 创建砖墙2. 给砖墙增加子弹击中的碰撞效果3. 给砖墙添加坦克不能通过的碰撞效果4. 添加石墙5. 添加玩家基地6. 最终效果坦克大战完善地图 我的素材放到了百度网盘里,里面还有原版…...