驅動開發的引入

1.引入

Linux內核的整體架構本就非常龐大,其包含的組件也非常多。而我們怎樣把需要的部分都包含在內核中呢?
一種方法是把所有需要的功能都編譯到Linux內核中。這會導致兩個問題,一是生成的內核會很大,二是如果我們要在現有的內核中新增或刪除功能,將不得不重新編譯內核。有沒有另一種機制可使得編譯出的內核本身并不需要包含所有功能,而在這些功能需要被使用的時候,其對應的代碼被動態地加載到內核中呢?
Linux 提供了這樣的機制,這種機制被稱為模塊(Module)。模塊具有這樣的特點,模塊本身不被編譯人內核映像,從而控制了內核的大小。模塊一旦被加載,它就和內核中的其他部分完全一樣。

Linux驅動開發就是編寫上面提到的模塊。

應用程序和 VFS 之間的接口是系統調用,而 VFS 與文件系統以及設備文件之間的接口是 file_operations結構體成員函數,這個結構體包含對文件進行打開、關閉、讀寫、控制的系列成員函數,關系如圖5.2所示。

由于字符設備的上層沒有類似于磁盤的ext2等文件系統,所以字符設備的file_operations成員函數就直接由設備驅動提供了file_operations正是字符設備驅動的核心。

塊設備有兩種訪問方法:

一種方法是不通過文件系統直接訪問裸設備,在 Linux內核實現了統一的 def blk_fops這一file_operations,它的源代碼位于fs/block_dev.c,所以當我們運行類似于“dd if=/dev/sdbl of-sdbl.img”的命令把整個 /dev/sdb1 裸分區復制到 sdbl.img的時候,內核走的是def blk_fops這個file_operations;

另外一種方法是通過文件系統來訪問塊設備,file_operations的實現則位于文件系統內,文件系統會把針對文件的讀寫轉換為針對塊設備原始扇區的讀寫。ext2、fat、Btrfs等文件系統中會實現針對VFS的file operations成員函數,設備驅動層將看不到file_operations的存在。

!外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳

2.struct file、struct inode

在設備驅動程序的設計中,一般面言,會關心fileinode這兩個結構體
file結構體代表一個打開的文件,系統中每個打開的文件在內核空間都有一個關聯的struct file。它由內核在打開文件時創建,并傳遞給在文件上進行操作的任何函數。在文件的在內核和驅動源代碼中,struct file的指針通常所有實例都關閉后,內核釋放這個數據結構。被命名為file或filp(即 file pointer)。

struct file {union {struct llist_node	fu_llist;struct rcu_head 	fu_rcuhead;} f_u;struct path			f_path;struct inode		*f_inode;	/* cached value */const struct file_operations	*f_op;/** Protects f_ep_links, f_flags.* Must not be taken from IRQ context.*/spinlock_t		    	f_lock;atomic_long_t			f_count;unsigned int 			f_flags;fmode_t			    	f_mode;struct mutex			f_pos_lock;loff_t					f_pos;struct fown_struct		f_owner;const struct cred		*f_cred;struct file_ra_state	f_ra;u64			f_version;
#ifdef CONFIG_SECURITYvoid				*f_security;
#endif/* needed for tty driver, and maybe others */void				*private_data;#ifdef CONFIG_EPOLL/* Used by fs/eventpoll.c to link all the hooks to this file */struct list_head		f_ep_links;struct list_head		f_tfile_llink;
#endif /* #ifdef CONFIG_EPOLL */struct address_space	*f_mapping;
} __attribute__((aligned(4)));	/* lest something weird decides that 2 is OK */

文件讀/寫模式mode、標志flags 都是設備驅動關心的內容,而私有數據指針 private_data在設備驅動中被廣泛應用,大多被指向設備驅動自定義以用于描述設備的結構體。

struct inode包含文件訪問權限、屬主、組、大小、生成時間、訪問時間、最后修改時間等信息。它是Linux管理文件系統的最基本單位,也是文件系統連接任何子目錄、文件的橋梁

struct inode {umode_t				i_mode;unsigned short		i_opflags;kuid_t				i_uid;kgid_t				i_gid;unsigned int		i_flags;#ifdef CONFIG_FS_POSIX_ACLstruct posix_acl	*i_acl;struct posix_acl	*i_default_acl;
#endifconst struct inode_operations	*i_op;struct super_block	*i_sb;struct address_space	*i_mapping;#ifdef CONFIG_SECURITYvoid			*i_security;
#endif/* Stat data, not accessed from path walking */unsigned long		i_ino;/** Filesystems may only read i_nlink directly.  They shall use the* following functions for modification:**    (set|clear|inc|drop)_nlink*    inode_(inc|dec)_link_count*/union {const unsigned int i_nlink;unsigned int __i_nlink;};dev_t			i_rdev;loff_t			i_size;struct timespec		i_atime;struct timespec		i_mtime;struct timespec		i_ctime;spinlock_t		i_lock;	/* i_blocks, i_bytes, maybe i_size */unsigned short      i_bytes;unsigned int		i_blkbits;blkcnt_t			i_blocks;#ifdef __NEED_I_SIZE_ORDEREDseqcount_t		i_size_seqcount;
#endif/* Misc */unsigned long		i_state;struct rw_semaphore	i_rwsem;unsigned long		dirtied_when;	/* jiffies of first dirtying */unsigned long		dirtied_time_when;struct hlist_node	i_hash;struct list_head	i_io_list;		/* backing dev IO list */
#ifdef CONFIG_CGROUP_WRITEBACKstruct bdi_writeback	*i_wb;		/* the associated cgroup wb *//* foreign inode detection, see wbc_detach_inode() */int			i_wb_frn_winner;u16			i_wb_frn_avg_time;u16			i_wb_frn_history;
#endifstruct list_head	i_lru;		/* inode LRU list */struct list_head	i_sb_list;struct list_head	i_wb_list;	/* backing dev writeback list */union {struct hlist_head	i_dentry;struct rcu_head		i_rcu;};u64				i_version;atomic_t		i_count;atomic_t		i_dio_count;atomic_t		i_writecount;
#ifdef CONFIG_IMAatomic_t		i_readcount; /* struct files open RO */
#endifconst struct file_operations	*i_fop;	/* former ->i_op->default_file_ops */struct file_lock_context	*i_flctx;struct address_space	i_data;struct list_head	i_devices;union {struct pipe_inode_info	*i_pipe;struct block_device	*i_bdev;struct cdev		*i_cdev;char			*i_link;unsigned		i_dir_seq;};__u32			i_generation;#ifdef CONFIG_FSNOTIFY__u32			i_fsnotify_mask; /* all events this inode cares about */struct hlist_head	i_fsnotify_marks;
#endif#if IS_ENABLED(CONFIG_FS_ENCRYPTION)struct fscrypt_info	*i_crypt_info;
#endifvoid			*i_private; /* fs or device private pointer */
};

對于表示設備文件的inode結構,struct cdev *i_cdev;字段包含設備編號。Linux內核設備編號分為主設備編號和次設備編號,前者為devt的高12位.后者為 devt的低 20位。

3.udev

**devfs(設備文件系統)**是由Linux2.4內核引入的,引入時被許多工程師給予了高度評價它的出現使得設備驅動程序能自主地管理自己的設備文件。具體來說,devs具有如下優點

  • 可以通過程序在設備初始化時在/dev目錄下創建設備文件,卸載設備時將它刪除
  • 設備驅動程序可以指定設備名、所有者和權限位,用戶空間程序仍可以修改所有者和權限位。
  • 不再需要為設備驅動程序分配主設備號以及處理次設備號,在程序中可以直接給register chrdev()傳遞0主設備號以獲得可用的主設備號,并在devfsregister()中指定次設備號。

盡管 devfs有這樣和那樣的優點,但是,在Linux2.6內核中,devfs被認為是過時的方法,并最終被拋棄了,udev取代了它。

在嵌人式系統中,也可以用 udev 的輕量級版本 mdev,mdev 集成于 busybox 中。

Linux設計中強調的一個基本觀點是機制和策略的分離。機制是做某樣事情的固定步驟、方法,而策略就是每一個步驟所采取的不同方式。機制是相對固定的,而每個步驟采用的策略是不固定的。機制是穩定的,而策略則是靈活的,因此,在Linux內核中,不應該實現策略。

熱插拔:

udev完全在用戶態工作利用設備加人或移除時內核所發送的熱插拔事件(Hotplug),在熱插拔時,設備的詳細信息會由內核通過netlink套接字發送出來,發出(Event)來工作的事情叫 uevent。udev的設備命名策略、權限控制和事件處理都是在用戶態下完成的,它利用從內核收到的信息來進行創建設備文件節點等工作

冷插拔:

udev就是采用這種方式接收netlink消息,并根據它的內容和用戶設置給udev的規則做匹配來進行工作的。這里有一個問題,就是冷插拔的設備怎么辦?冷插拔的設備在開機時就存在,在udev啟動前已經被插入了。對于冷插拔的設備,Linux內核提供了sysfs下面一個uevent節點,可以往該節點寫一個“add”,導致內核重新發送netlink,之后udev就可以收到冷插拔的netlink 消息了。

udev自動加載驅動模塊的原理
#設備被發現時發送事件:當硬件設備被插入系統時,內核會檢測到該設備,并通過kobject_uevent函數向用戶空間發送一個uevent事件。這個事件包含了設備的相關信息,如設備的Vendor ID、Product ID等。
#udev監聽事件并處理:udev守護進程在用戶空間運行,監聽這些uevent事件。udev根據事件中的設備信息,查找/lib/modules/uname-r/modules.alias文件,確定需要加載的驅動模塊。
#加載驅動模塊:udev通過調用modprobe命令加載對應的驅動模塊。modprobe會根據模塊的依賴關系,自動加載所有必要的依賴模塊。#注意:/lib/modules/uname-r/modules.alias文件的內容是在內核模塊編譯和安裝時由make modules_install命令生成的。它包含了模塊的別名映射,用于幫助udev或其他工具根據設備的硬件信息找到并加載正確的驅動模塊。模塊編譯進內核時不會出現在modules.alias文件中,只有作為可加載模塊編譯時才會被包含在內。insmod命令用于手動加載模塊,但不會修改modules.alias文件。

**udev的設計者認為inux應該在設備被發現的時候加載驅動模塊,而不是當它被訪問的時候。**udev的設計者認為devs所提供的打開/dev節點時自動加載驅動的功能對一個配置正確的計算機來說是多余的,系統中所有的設備都應該產生熱插拔事件并加載恰當的驅動,而udev能注意到這點并且為它創建對應的設備節點。

4.sysfs文件系統與Linux設備模型

Linux 2.6以后的內核引人了sysfs 文件系統,sys被看成是與 proc、devfs和 devpty 同類別的文件系統,該文件系統是一個虛擬的文件系統,它可以產生一個包括所有系統硬件的層級視圖,與提供進程和狀態信息的proc文件系統十分類似。

sysfs把連接在系統上的設備和總線組織成為一個分級的文件,它們可以由用戶空間存取,向用戶空間導出內核數據結構以及它們的屬性。sysfs的一個目的就是展示設備驅動模型中各組件的層次關系,其頂級目錄包括 block、bus、dev、devices、class、fs、kernel、power和 frmware 等。

block目錄包含所有的塊設備;devices目錄包含系統所有的設備,并根據設備掛接的總線類型組織成層次結構;bus日錄包含系統中所有的總線類型;class目錄包含系統中的設備類型(如網卡設備、聲卡設備、輸人設備等)。

外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳

在 /sys/bus的 pci等子目錄下,又會再分出 drivers和devices目錄,而devices 目錄中的文件是對/sys/devices目錄中文件的符號鏈接。同樣地,/sys/class目錄下也包含許多對/sys/devices下文件的鏈接。如圖5.3所示,Linux設備模型與設備、驅動、總線和類的現實狀況是直接對應的,也正符合Linux2.6以后內核的設備模型。

大多數情況下,Linux2.6以后的內核中的設備驅動核心層代碼作為“幕后大佬”可處理好這些關系,內核中的總線和其他內核子系統會完成與設備模型的交互,這使得驅動工程師在編寫底層驅動的時候幾乎不需要關心設備模型,只需要按照每個框架的要求,"填鴨式地填充xxx driver里面的各種回調函數,xxx是總線的名字,在 Linux 內核中,分別使用 bus typedevice driverdevice 來描述總線、驅動和設備,這3個結構體定義于include/linux/device.h頭文件中,其定義如代碼清單5.7所示。

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;
};
struct device_driver {const char		*name;  	// 驅動程序的名稱struct bus_type		*bus;   // 驅動程序所屬的總線類型(如 platform_bus_type、i2c_bus_type 等)// 內核通過總線類型將驅動程序與設備匹配struct module		*owner; // 指向擁有該驅動程序的模塊(通常使用 THIS_MODULE)const char		*mod_name;	// 用于內置模塊的名稱(通常用于模塊卸載時)bool suppress_bind_attrs;	/* disables bind/unbind via sysfs */// 如果為 true,則禁用通過 sysfs 進行驅動程序的綁定和解綁操作enum probe_type probe_type;	// 設備探測類型,用于控制探測行為(如同步探測或異步探測)const struct of_device_id	*of_match_table;	// 設備樹匹配表,用于支持設備樹(Device Tree)的設備匹配const struct acpi_device_id	*acpi_match_table;	// ACPI 匹配表,用于支持 ACPI 設備的匹配int (*probe) (struct device *dev);		// 設備探測函數,當驅動程序與設備匹配成功時調用int (*remove) (struct device *dev);		// 設備移除函數,當設備從系統中移除時調用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; 	// 驅動程序私有數據
};
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, devicecore doesn't touch it */void		*driver_data;		/* Driver data, set and get withdev_set/get_drvdata */struct dev_links_info	links;struct dev_pm_info	power;struct dev_pm_domain	*pm_domain;#ifdef CONFIG_GENERIC_MSI_IRQ_DOMAINstruct irq_domain	*msi_domain;
#endif
#ifdef CONFIG_PINCTRLstruct dev_pin_info	*pins;
#endif
#ifdef CONFIG_GENERIC_MSI_IRQstruct list_head	msi_list;
#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;const struct attribute_group **groups;	/* optional groups */void	(*release)(struct device *dev);struct iommu_group	*iommu_group;struct iommu_fwspec	*iommu_fwspec;bool			offline_disabled:1;bool			offline:1;
};

注點:總線、驅動和設備最終都會落實為sysfs中的1個目錄,因為進一步追蹤代碼會發現,它們實際上都可以認為是 kobject的派生類,kobject可看作是所有總線、設備和驅動的抽象基類,1個kobject對應sys中的1個目錄.

總線設備和驅動中的各個attribute 直接落實為sysfs中的一個文件,attribute 會伴隨著show()store()這兩個函數。分別用于讀寫該attribute 對應的sysfs文件。

下面給出了 attribute、bus attribute、driver attribute 和 device attribute 這幾個結構體的定義。

struct attribute {const char		*name;umode_t			mode;
#ifdef CONFIG_DEBUG_LOCK_ALLOCbool			ignore_lockdep:1;struct lock_class_key	*key;struct lock_class_key	skey;
#endif
};struct bus_attribute {struct attribute	attr;ssize_t (*show)(struct bus_type *bus, char *buf);ssize_t (*store)(struct bus_type *bus, const char *buf, size_t count);
};struct device_attribute {struct attribute	attr;ssize_t (*show)(struct device *dev, struct device_attribute *attr,char *buf);ssize_t (*store)(struct device *dev, struct device_attribute *attr,const char *buf, size_t count);
};struct driver_attribute {struct attribute attr;ssize_t (*show)(struct device_driver *driver, char *buf);ssize_t (*store)(struct device_driver *driver, const char *buf,size_t count);
};

事實上sysfs中的目錄來源于 bus type、device_driver、device,而目錄中的文件則來源attribute.

Linux內核中也定義了一些快捷方式以方便attribute的創建工作:

#define BUS_ATTR(_name, _mode, _show, _store)	\struct bus_attribute bus_attr_##_name = __ATTR(_name, _mode, _show, _store)
#define BUS_ATTR_RW(_name) \struct bus_attribute bus_attr_##_name = __ATTR_RW(_name)
#define BUS_ATTR_RO(_name) \struct bus_attribute bus_attr_##_name = __ATTR_RO(_name)#define DRIVER_ATTR(_name, _mode, _show, _store) \struct driver_attribute driver_attr_##_name = __ATTR(_name, _mode, _show, _store)
#define DRIVER_ATTR_RW(_name) \struct driver_attribute driver_attr_##_name = __ATTR_RW(_name)
#define DRIVER_ATTR_RO(_name) \struct driver_attribute driver_attr_##_name = __ATTR_RO(_name)
#define DRIVER_ATTR_WO(_name) \struct driver_attribute driver_attr_##_name = __ATTR_WO(_name)#define DEVICE_ATTR(_name, _mode, _show, _store) \struct device_attribute dev_attr_##_name = __ATTR(_name, _mode, _show, _store)
#define DEVICE_ATTR_RW(_name) \struct device_attribute dev_attr_##_name = __ATTR_RW(_name)
#define DEVICE_ATTR_RO(_name) \struct device_attribute dev_attr_##_name = __ATTR_RO(_name)
#define DEVICE_ATTR_WO(_name) \struct device_attribute dev_attr_##_name = __ATTR_WO(_name)
#define DEVICE_ULONG_ATTR(_name, _mode, _var) \struct dev_ext_attribute dev_attr_##_name = \{ __ATTR(_name, _mode, device_show_ulong, device_store_ulong), &(_var) }
#define DEVICE_INT_ATTR(_name, _mode, _var) \struct dev_ext_attribute dev_attr_##_name = \{ __ATTR(_name, _mode, device_show_int, device_store_int), &(_var) }
#define DEVICE_BOOL_ATTR(_name, _mode, _var) \struct dev_ext_attribute dev_attr_##_name = \{ __ATTR(_name, _mode, device_show_bool, device_store_bool), &(_var) }
#define DEVICE_ATTR_IGNORE_LOCKDEP(_name, _mode, _show, _store) \struct device_attribute dev_attr_##_name =		\__ATTR_IGNORE_LOCKDEP(_name, _mode, _show, _store)

比如,我們在 drivers/base/bus.c文件中可以找到這樣的代碼

static BUS_ATTR(uevent, S_IWUSR, NULL, bus_uevent_store);static BUS_ATTR(drivers_probe, S_IWUSR, NULL, store_drivers_probe);
static BUS_ATTR(drivers_autoprobe, S_IWUSR | S_IRUGO,show_drivers_autoprobe, store_drivers_autoprobe);

而在 /sys/bus/platform 等里面就可以找到對應的文件

[root@100ask:/sys/bus/platform]# ls
devices  drivers  drivers_autoprobe  drivers_probe  uevent

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/898821.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/898821.shtml
英文地址,請注明出處:http://en.pswp.cn/news/898821.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

AI日報 - 2025年3月24日

🌟 今日概覽(60秒速覽) ▎🤖 AGI突破 | Lyra生物序列建模架構效率驚人 在100生物任務中達最優,推理速度提升高達12萬倍 ▎💼 商業動向 | OpenAI用戶破4億,Meta與Reliance探討AI合作 生態擴展與全…

VMware上對CentOS7虛擬機進行磁盤擴容、縮容

在VMware 17 Pro上對CentOS 7虛擬機進行磁盤擴容,同時保證原先部署的軟件正常使用,可以按照以下步驟進行操作: 一、擴容 步驟一:關閉虛擬機并在VMware中擴展磁盤容量 關閉虛擬機:在VMware Workstation 17 Pro中&…

.gitignore使用指南

.gitignore使用指南 目錄 什么是.gitignore為什么需要.gitignore如何創建.gitignore文件.gitignore文件的語法規則 忽略單個文件忽略目錄忽略特定類型的文件不忽略特定文件或目錄遞歸匹配 示例.gitignore文件注意事項更多特殊場景匹配規則 忽略多個特定后綴的文件忽略特定目錄…

OpenCV旋轉估計(3)幫助構建一個最大生成樹(Maximum Spanning Tree)函數findMaxSpanningTree()

操作系統:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 編程語言:C11 算法描述 cv::detail::findMaxSpanningTree 是 OpenCV 中用于圖像拼接工作流的一個函數,它幫助構建一個最大生成樹(Maximum Spanni…

Android在kts中簡單使用AIDL

Android在kts中簡單使用AIDL AIDL相信做Android都有所了解,跨進程通信會經常使用,這里就不展開講解原理跨進程通信的方式了,最近項目換成kts的方式,于是把aidl也換成了統一的方式,其中遇到了很多問題,這里…

論文閱讀:2024-NAACL Semstamp、2024-ACL (Findings) k-SemStamp

總目錄 大模型安全相關研究:https://blog.csdn.net/WhiffeYF/article/details/142132328 Semstamp: A semantic watermark with paraphrastic robustness for text generation https://aclanthology.org/2024.naacl-long.226/ k-SemStamp: A Clustering-Based Semantic Wate…

物化視圖詳解:數據庫性能優化的利器

物化視圖(Materialized View)作為數據庫性能優化的核心手段,通過預計算和存儲查詢結果,顯著提升了復雜查詢的效率。本文將深入剖析物化視圖的工作原理、應用場景及最佳實踐,幫助企業在合適的場景中充分發揮其性能優勢。…

快速入手:Nacos融合SpringCloud成為注冊配置中心

快速入手:Nacos融合SpringCloud成為注冊配置中心 前言安裝Nacos項目搭建添加配置啟動類添加注解運行項目服務調用RestTemplate 模式FeignClient 模式 Gateway 網關 前言 Spring Cloud是一系列框架的集合,提供了微服務架構下的各種解決方案,如…

2025年2月-3月后端go開發找工作感悟

整體感悟 目標 找工作首先要有一個目標,這個目標盡可能的明確,比如我要字節、拼多多之類的公司,還是要去百度、滴滴這樣的,或者目標是創業公司。但是這個目標是會動態調整的,有可能我們的心態發生了變化,一…

Python | 如何在Pandas中刪除常量列

在數據分析中,經常會遇到數據集中始終具有常量值的列(即,該列中的所有行包含相同的值)。這樣的常量列不提供有意義的信息,可以安全地刪除而不影響分析。 如: 在本文中,我們將探索如何使用Pyth…

5.高頻加熱的原理與常用集成電路介紹

一、高頻加熱的類型 利用高頻電源加熱通常由兩種方法:電介質加熱(被加熱物體絕緣)與感應加熱(被加熱物體導電),詳細解釋如下: 電介質加熱(利用高頻電壓的高頻電場導致物體自身分子摩…

串口通信與Modbus通信的區別和聯系

一、定義與定位 1?、串口通信? 是物理層的硬件接口標準,用于實現設備間的?串行數據傳輸?,常見類型包括RS-232、RS-485和RS-422?35。其功能是完成并行數據與串行信號的轉換,并定義電氣特性(如電平、傳輸速率)?。…

Linux生產者消費者模型

Linux生產者消費者模型 Linux生產者消費者模型詳解生產者消費者模型生產者消費者模型的概念生產者消費者模型的特點生產者消費者模型優點 基于BlockingQueue的生產者消費者模型基于阻塞隊列的生產者消費者模型模擬實現基于阻塞隊列的生產消費模型基礎實現生產者消費者步調調整條…

【中文翻譯】第9章-The Algorithmic Foundations of Differential Privacy

由于GitHub項目僅翻譯到前5章,我們從第6章開始通過大語言模型翻譯,并導出markdown格式。 大模型難免存在錯漏,請讀者指正。 教材原文地址:https://www.cis.upenn.edu/~aaroth/Papers/privacybook.pdf 9 差分隱私與計算復雜度 到目…

【AI大模型】搭建本地大模型GPT-NeoX:詳細步驟及常見問題處理

搭建本地大模型GPT-NeoX:詳細步驟及常見問題處理 GPT-NeoX是一個開源的大型語言模型框架,由EleutherAI開發,可用于訓練和部署類似GPT-3的大型語言模型。本指南將詳細介紹如何在本地環境中搭建GPT-NeoX,并解決過程中可能遇到的常見問題。 1. 系統要求 1.1 硬件要求 1.2 軟…

Unity跨平臺構建快速回顧

知識點來源:人間自有韜哥在,豆包 目錄 一、發布應用程序1. 修改發布必備設置1.1 打開設置面板1.2 修改公司名、游戲項目名、版本號和默認圖標1.3 修改 Package Name 和 Minimum API Level 2. 發布應用程序2.1 配置 Build Settings2.2 選擇發布選項2.3 構…

低配電腦暢玩《怪物獵人:荒野》,ToDesk云電腦優化從30幀到144幀?

《怪物獵人:荒野(Monster Hunter Wilds)》自2025年正式發售以來已取得相當亮眼的成績,僅用三天時間便輕松突破800萬銷量,目前順利蟬聯周榜冠軍;憑借著開放世界的宏大場景和豐富的狩獵玩法,該游戲…

Flink基礎簡介和安裝部署

文章目錄 一、Flink基礎簡介1、什么是Flink2、Flink流處理特性3、Flink四大基石4、Flink中的角色 二、Flink集群搭建1、Local模式①上傳Flink安裝包②啟動交互窗口③提交任務測試④訪問WebUI頁面查看④退出停止集群 一、Flink基礎簡介 1、什么是Flink Flink是?個分布式&#…

【2025】基于ssm+jsp的二手商城系統設計與實現(源碼、萬字文檔、圖文修改、調試答疑)

基于SSMJSP的二手商城系統設計與實現系統功能結構圖: 課題背景 隨著經濟的發展和人們生活水平的提高,二手交易市場日益活躍。人們對于閑置物品的處理方式逐漸從傳統的廢品回收轉變為通過二手交易平臺進行再利用。這種交易模式不僅能夠幫助用戶節省開支&a…

幻影星空亮相CAAPA北京展 引領文旅產業升級轉型

3月19日,中國游藝機游樂園協會(CAAPA)主辦的2025中國(北京)國際游樂設施設備博覽會及2025北京國際旅游休閑娛樂產業博覽會在北京盛大啟幕。在這場行業盛會上,廣州卓遠旗下的“幻影星空”品牌以創新性的虛擬…