分布式wordpress/深圳的seo网站排名优化

分布式wordpress,深圳的seo网站排名优化,晋江网站建设哪家好,加盟凡科建站高级字符设备进阶 1.一个完整的IO过程包含以下几个步骤:1应用程序向操作系统发起IO调用请求(系统调用);2操作系统准备数据,把IO设备的数据加载到内核缓冲区;3操作系统拷贝数据,把内核缓冲区的数据从内核空间拷贝到应用…
高级字符设备进阶

1.一个完整的IO过程包含以下几个步骤:1应用程序向操作系统发起IO调用请求(系统调用);2操作系统准备数据,把IO设备的数据加载到内核缓冲区;3操作系统拷贝数据,把内核缓冲区的数据从内核空间拷贝到应用空间。IO模型有阻塞IO、非阻塞IO、IO多路复用、信号驱动IO、异步IO,其中前四个被称之为同步IO,只有最后一种是真正的异步IO,因为无论是多路复用IO还是信号驱动模型,IO操作的第2个阶段都会引起用户线程阻塞,也就是内核进行数据拷贝的过程都会让用户线程阻塞。示意图如下:

  • 阻塞IO:

  • 非阻塞IO:

  • IO多路复用:IO多路复用可以实现一个进程监视多个文件描述符,一旦其中一个文件描述符准备就绪,就通知应用程序进行相应的操作

  • 信号驱动IO:信号驱动IO不需要应用程序去查询设备的状态。一旦设备准备就绪,就触发SIGIO信号,该信号会通知应用程序数据已经到来

  • 异步IO:

2.等待队列:等待队列是内核实现阻塞和唤醒的内核机制,等待队列以循环链表为基础结构,链表头和链表项分别为等待队列头和等待队列元素,整个等待队列由等待队列头进行管理。等待队列头使用结构体 wait_queue_head_t来表示, 等待队列头就是一个等待队列的头部,Linux中与等待队列定义在文件include/linux/wait.h里面,如下图:

结构体wait_queue_entry_t表示等待队列项,结构体内容如下:

list_head的结构为:

所以整个等待队列的结构如下图所示:

初始化一个等待队列头的方法有两种:1先定义一个等待队列头wait_queue_head_t head;,然后用void init_waitqueue_head(wait_queue_head_t *q)函数将其初始化;2使用宏定义DECLARE_WAIT_QUEUE_HEAD(name)一次性定义并初始化一个等待队列头,这里的name的类型是结构体 wait_queue_head_t。等待队列项一般使用宏DECLARE_WAITQUEUE(name, task)来创建,name就是等待队列项的名字,其类型是结构体wait_queue_entry_t。task表示这个等待队列项属于哪个任务(进程),一般设置为current,在Linux内核中current相当于一个全局变量,表示当前进程。因此DECLARE_WAITQUEUE就是给当前正在运行的进程创建并初始化了一个等待队列项。例如:DECLARE_WAITQUEUE(wait,current);表示给当前正在运行的进行创建一个名为wait的等待队列项,再使用add_wait_queue(&wq,&wait);表示将wait这个等待队列项加到wq这个等待队列当中。void add_wait_queue(wait_queue_head_t *q, wait_queue_entry_t *wait)函数可将队列项加入某个队列中,q是待加入队列的等待队列(头),wait是要加入的等待队列项。void remove_wait_queue(wait_queue_head_t *q, wait_queue_entry_t *wait)函数用于从等待队列中删除等待队列项,其中q是目标队列的等待队列头,wait是要删除的等待队列项。当设备可以使用的时候就要唤醒进入休眠态的进程,唤醒可以使用如下两个函数:wak_up(wait_queue_head_t *q)函数用于唤醒所有休眠进程;wake_up_interruptible(wait_queue_head_t *q)用于唤醒可中断的休眠进程。等待事件:1 wait_event (wq,condition)宏,不可中断的阻塞等待,让调用进程进入不可中断的睡眠状态, 在等待队列里面睡眠直到condition变成真,被内核唤醒,这里的wq的类型是结构体wait_queue_head_t,在condition为1时该函数不会阻塞而是会立即返回。2 wait_event_interruptible(wq,condition)宏,可中断的阻塞等待,让调用进程(当前进程)进入可中断的睡眠状态,直到condition 变成真被内核唤醒或信号打断唤醒,这里的wq的类型是结构体wait_queue_head_t,在condition为1时该函数不会阻塞而是会立即返回。等待队列的使用方法为:1.初始化等待队列头,并将条件置成假(condition=0);2.在需要阻塞的地方调用wait_event(),使进程进入休眠;3.当条件满足时,需要解除休眠,先将条件置成真(condition=1),然后调用wake_up函数唤醒等待队列中的休眠进程(可参考讯为Linux驱动视频第四期P2)。

3.应用程序可以使用如下所示示例代码来实现阻塞访问:fd=open("/dev/xxx_dev”,0RDWR);,ret =read(fd,&data,sizeof(data));,可以看出对于设备驱动文件的默认读取方式就是阻塞式的。如果应用程序要采用非阻塞的方式来访问驱动设备文件,可以使用如下所示代码:fd =open("/dev/xxx_dev",O_RDWR|O_NONBLOCK);、ret = read(fd, &data, sizeof(data)),上述代码在使用open数打开“/dev/xxx_dev”设备文件的时候添加了参数“O_NONBLOCK”表示以非阻塞方式打开设备,这样从设备中读取数据的时候就是非阻塞方式的了。在驱动程序中的读写函数里面,他们的参数中有一个struct file *file,这个结构体有一个成员file->flags用来记录打开文件时传入的O_RDWR|O_NONBLOCK,可以在驱动程序中根据这个来判断是否是以非阻塞方式实现IO(可参考讯为Linux驱动视频第四期P3)。

4.在应用层使用select(int select(int nfds, fd_set *readfds, fd_set *writefds,fd_set *exceptfds, struct timeval *timeout);)和poll(int poll(struct pollfd *fds, nfds_t nfds, int timeout);)等系统调用会触发设备驱动中的poll()函数被执行,file_operations结构体中有一个函数指针成员poll:__poll_t (*poll) (struct file *, struct poll_table_struct *);,一般在驱动程序中将其绑定到驱动程序中自定义的poll函数以实现应用层和驱动层的互通。驱动中poll函数要进行两项工作,第一项工作:对可能引起设备文件状态变化的等待队列调用poll_wait(void poll_wait(struct file *filp, wait_queue_head_t *queue, poll_table *wait);),该函数将对应的等待队列头添加到poll_table,等待特定事件的发生(如设备准备好读取或写入数据),poll_table 结构用于跟踪该进程的等待状态。poll_wait 函数本身是非阻塞的,它只是将当前进程加入到等待队列中,实际上阻塞当前进程的工作是在内核中的内核中的其他函数(do_poll)中完成的,事件发生时需要调用wake_up_interruptible等函数来唤醒被阻塞的进程。当应用层调用 poll 时,内核会依次检查文件描述符对应的设备是否已经准备好(例如是否可以读取数据,当应用层调用poll()函数时,它会遍历传入的文件描述符集合,并将每个文件描述符对应的设备驱动的poll()函数调用一遍)。如果设备尚未准备好(例如没有数据可读),进程会被加入到等待队列中,并且会进入阻塞状态。第二项工作:返回表示是否能对设备进行无阻塞读写访问的掩码。Linux中与poll有关的定义在include/linux/poll.h中。如下图所示(可参考讯为Linux驱动视频第四期P4,及实验18_poll):

5.应用程序使用信号驱动IO的步骤:1注册信号处理函数,应用程序使用signal函数(sighandler_t signal(int signum, sighandler_t handler);)来注册SIGIO信号的信号处理函数,SIGIO信号用于通知进程与IO相关的事件。这是一个事件驱动信号,通常用于告知进程,某个文件描述符已经准备好进行IO操作(例如,数据可以读取或可以写入),使得进程可以在不阻塞的情况下处理IO操作;2设置能够接收这个信号的进程,通过fcntl(fd,F_SETOWN,getpid());实现,这句的作用是将指定的文件描述符fd的IO操作的信号通知目标设置为当前进程。这意味着,当该文件描述符上的IO事件(如可读、可写等)发生时,操作系统会发送一个信号(通常是SIGIO)给指定的进程;3开启信号驱动IO,通常使用fcnt1的F_SETFL命令打开FASYNC标志,如:flags=fcntl(fd,F_GETFD);,fcntl(fd,F_SETFL,flags|FASYNC);。驱动程序中要执行以下步骤:1当应用程序开启信号驱动IO时,会触发驱动中的fasync函数,所以首先将file_operations结构体中的成员fasync(int (*fasync) (int, struct file *, int);)绑定到在驱动程序中自定义的fasync函数。2在自定义的fasync函数中调用fasync_helper函数来操作fasync_struct结构体,fasync_helper函数原型为int fasync_helper(int fd, struct file * filp, int on, struct fasync_struct **fapp),该函数用于管理与文件描述符相关的IO事件,它根据文件描述符的标志位,控制是否将IO事件的信号(如SIGIO)发送给进程,fasync_helper会在文件描述符注册时,通过fasync_struct将文件描述符与进程进行绑定,确保在文件描述符准备好时,能够通知进程(通过发送SIGIO信号)。其中fd是这是需要设置IO的文件描述符,filp是指向struct file结构体的指针,该结构体代表一个已经打开的文件,filp是内核中的文件句柄,用于表示内核中的文件对象,on参数指定是否启用IO,fapp是一个指向fasync_struct指针的指针,fasync_struct用于存储与IO相关的数据,如进程的异步通知队列。3当设备准备好的时候,驱动程序需要调用kill_fasync函数通知应用程序,此时应用程序的SIGIO信号处理函数就会被执行,kill_fasync负责发送指定的信号。函数原型为void kill_fasync(struct fasync_struct **fp, int sig, int band);,其中fp是要操作的fasync_struct,sig是要发送的信号,band在可读的时候设置成POLLIN,可写的时候设置成POLLOUT(可参考讯为Linux驱动视频第四期P5)。

6.Linux内核定时器是一种基于未来时间点的计时方式,基于未来时间点的计时是以当前时刻为计时开始的时间点,以未来的某一时刻为计时的终点。比如,现在是早上7点,我用手机定时五分钟,定时时间就是7点+5分钟=7点5分。内核定时器的精度不高,所以不能作为高精度定时器使用,并且内核定时器不是周期性运行的,到计时终点后会自动关闭。如果想要实现周期性定时,就需要定时处理函数中重新开启定时器。Linux内核使用timer_list结构体表示内核定时器(这个定时器只能用在内核,用户空间的定时器相关函数是timer_create()、timer_settime()等),timer_list定义在include/linux/timer.h头文件当中,定义如下:

在timer_list结构体中,expires为计时终点的时间,单位是节拍数。Linux内核中有一个宏HZ,这个宏用来表示一秒钟对应的节拍的数量,利用这个宏就可以把时间转换成节拍数。比如定时一秒钟换成节拍数就是expires=jiffies+5*HZ,其中jiffies为系统当前时间对应的节拍数。宏HZ的值是可以设置的,也就是说一秒钟对应多少个节拍数是可以设置的。进入内核源码目录,打开menuconfig图形化配置界面,按照->Kernel Features->Timer frequency(<choice>[=y])就可以设置。全局变量jiffies用来记录自系统启动以来产生的节拍的总数。系统启动时,内核将该变量初始化为0,此后每次时钟中断处理程序都会增加该变量的值。 因为一秒内时钟中断的次数为HZ(节拍数),所以jiffies一秒内增加的值也就为HZ(节拍数),系统运行时间以秒为单位计算, 就等于 jiffies/HZ。jiffies=seconds*HZ。jiffies定义在文件include/linux/jiffies.h 中,定义如下(jiffies_64和jiffies分别对应64和32位系统):

与全局变量jiffies相关的转换函数如下图:

内核定时器的使用步骤为:1初始化内核定时器(struct timer_list),可以直接使用宏DEFINE_TIMER(_name, _function)来初始化内核定时器(对应于5以上的内核版本),其中_name为定时器名字,_function为回调函数,然后用_name.expires=jiffies_64 +msecs_to_jiffies(ms);来设置定时时间。2调用void add_timer(struct timer_list *timer)函数向Linux内核注册定时器。3在驱动出口函数中调用int del_timer(struct timer_list * timer)删除定时器。4如果想修改定时时间,可以调用int mod_timer(struct timer_list *timer, unsigned long expires)进行修改(可参考讯为Linux驱动视频第四期P7、P8)。

7.Linux中的dmesg命令用于显示内核的环形缓冲区(ring buffer)中的消息,这些消息通常是内核在系统启动时、驱动加载时、硬件设备初始化时等阶段产生的日志信息。通过dmesg命令,可以查看到系统启动过程中的各种硬件设备识别、驱动加载以及其他内核层面的信息。dmesg命令的参数如下图所示:

在ubuntu中直接执行insmod命令安装内核模块是看不到打印信息的,而cat /proc/kmsg 命令用于查看 Linux 系统中的内核日志,它直接从 /proc/kmsg 文件读取内核缓冲区中的日志消息,实时显示系统运行时内核产生的实时日志输出在终端。所以可以开启两个终端在其中一个中执行cat /proc/kmsg 命令,在另一个终端进行内核模块的安装就能看到打印信息了。

8.Linux内核日志的打印是有打印等级的,可以通过调整内核的打印等级来控制打印日志的输出,使用命令cat /proc/sys/kernel/printk可以查看默认的打印等级。如下图所示:

打印等级有四个数字,这四个数字分别代表console_loglevel(当前控制台日志等级,它控制了内核消息被输出到控制台的最低日志等级)、default_message_loglevel(默认消息等级,若没指定输出日志的等级,内核将使用这个默认值)、minimum_console_loglevel(控制台日志等级可被设置的最小值(最高优先级))、default_console_loglevel(默认控制台日志的等级)。这四个等级定义在kernel/printk/printk.c文件当中,如下图所示:

Linux内核提供了8中不同的日志级别,分别对应0到7,数字越小级别就越高,定义在include/linux/kern_levels.h文件当中。如下图:

在内核打印的时候,只有数值小于(级别高)当前系统的设置的打印等级,打印信息才可以被显示到控制台上,大于或者等于(级别低)的打印信息不会被显示到终端上。可以用以下三种方法来修改Linux内核打印等级:1通过make menuconfig图形化配置界面修改默认的日志级别default_console_loglevel,menuconfig图形化配置界面路径:Kernel hacking ->printk and dmesg options ->Default message log level();2在调用printk的时候设置打印等级,例如printk(KERN_EMERG "hello!\n”);;3使用echo直接修改打印等级,具体步骤为:首先可以用命令cat /proc/sys/kernel/printk查看内核打印等级,然后按需求修改控制台打印等级。例如要屏蔽所有打印,只需要将第一个数值调整到0即可,使用命令为echo 0 4 1 7 >/proc/sys/kernel/printk。再如要打开控制台的所有打印,使用命令为echo 7 4 1 7 >/proc/sys/kernel/printk。

9.用户空间的lseek函数:off_t lseek(int fd,off_t offset,int whence)其中,fd为文件描述符,offset为偏移量(单位为字节,可正可负),whence的值可为SEEK_SET、SEEK_CUR、SEEK_END分别表示文件开头、文件当前偏移位置、文件结尾,这个函数可以用来改变文件的当前偏移位置,若成功返回文件当前相对于文件开头的偏移量失败则返回-1,同一个文件“读”和“写”使用的是同一偏移位置(lseek函数还可以用来查询当前文件的大小,如lseek(fd,0,SEEK_END)返回的就是当前文件大小,还可以用此函数拓展文件大小,但是要想真正拓展文件大小,必须引起IO操作)。在用户空间中调用lseek函数会调用驱动中的file_operations结构体中的成员loff_t (*llseek) (struct file *, loff_t, int);,可以在驱动程序中自定义llseek函数并将其绑定到file_operations的成员llseek,如下图:

同时需要对驱动中的read和write进行修改,驱动中的read函数原型为ssize_t (*read)(struct file *filp,char __user *buffer,size_t size,loff_t *p);,其中file指向打开的文件,buffer为存放数据的缓冲区,size为要读取的数据长度,p为读的位置,也就是相对于文件的开头的偏移,在读完数据以后,这个指针要进行移动,动的值为读取信息的长度。file结构体中有一个成员file-> f_pos指向文件当前偏移量。一个read函数示例如下图:

驱动中的write函数原型为ssize_t (*write)(struct file *filp, const char __user *buffer, size_t count, loff_t *ppos);,其中file指向打开的文件,buffer为写入数据的缓冲区,size为要写入的数据长度,p为写的位置,也就是相对于文件的开头的偏移。下图是一个例子(可参考讯为Linux驱动视频第四期P11):

10.Linux中对非数据的操作通常通过ioctl操作来实现。应用层的ioctl函数在头文件sys/ioctl.h中定义,函数原型为int ioctl(int fd,unsigned int cmd, unsigned long request, ...);,其中fd为打开设备节点获得的文件描述符,cmd为给驱动传递的命令,后面为可变参数,该函数调用成功返回0失败返回-1。调用用户空间的ioctl最终会调用驱动程序中file_operations结构体中的成员long (*unlocked_ioctl) (struct file *file, unsigned int cmd, unsigned long arg);,unlocked_ioctl的三个参数和ioctl的参数是对应的。ioctl或unlocked_ioctl函数中参数cmd命令的格式如下图:

上图中,设备类型代表一类设备,一般用一个字母或者一个8bit的数字来表示;序列号代表的是这类设备的第几个命令;方向表示命令的方向,如:只读(10)、只写(01)、写读(11)、无数据(00);数据大小表示用户数据的大小,注意这里传递的不是数字,而是数据类型,比如要传递四个字节,就可以写入int。Linux定义了几个宏来构建和分解上面的cmd,ioctl的参数cmd的合成宏包括:合成没有数据传递的命令的宏_IO(type,nr)、合成从驱动中读取数据的命令的宏_IOR(type,nr,size)、合成向驱动中写数据的命令的宏_IOW(type,nr,size)、合成先写入数据再读取数据的命令的宏_IOWR(type,nr,size),其中type为设备类型,nr为序列号,size为数据尺寸。ioctl的参数cmd的分解宏包括:获取方向的宏_IOC_DIR(nr)、获取设备类型的宏_IOC_TYPE(nr)、获取序列号的宏_IOC_NR(nr)、获取数据尺寸的宏_IOC_SIZE(nr),其中nr为前面合成的cmd命令。当想要通过ioctl函数传递多个参数时,可以将这些参数封装成一个结构体,然后传入结构体的地址即可(可参考讯为Linux驱动视频第四期P15)。

11.可以通过静态库将驱动程序进行封装,提供API函数供应用层使用(可参考讯为Linux驱动视频第四期P17)。静态库的制作及使用:首先把将要制作成静态库的.c文件转换成.o文件:如gcc -c add.c -o add.o,然后使用ar工具制作静态库:如ar -rcs libname.a add.o sub.o div.o(-r选项会将指定的目标文件add.o、sub.o、div.o插入到 libname.a文件中。如果这些目标文件已经存在于该文件中,则会被更新,如果libname.a文件不存在,则使用-c将创建一个新的文件,-s表示创建文件时加入符号表,该符号表用于链接时解析符号引用),最后编译静态库到可执行文件中:如gcc test.c libname.a -o a.out(注意在命令中静态链接库位于源程序后面,否则编译不成功,这与链接器工作时的算法有关,源程序用到的静态库函数需要声明,否则会报警告,一般可以写入头文件来声明)(静态库都以.a结尾,默认库名以lib开头,如果在生成可执行文件中没有加入静态库,而源程序需要用到静态库的某些函数,则编译时会在链接阶段报错,一般程序编译过程中只会在4个步骤中的编译阶段或链接阶段报错,前者有报错的行号后者没有)。

12.优化驱动的稳定性和效率:通过在一些函数调用后面添加错误处理可以增加程序的稳定性,但这样会导致增加许多if条件分支。现在的CPU都有I-Cache和流水线机制,运行当前的指令时,I-Cache会预读取后面的指令,从而提升效率。但是如果条件分支的结果是跳转到了其他指令,那预取下一条指令就浪费时间了。如果使用likely和unlikely来让编译器总是将大概率执行的代码放在靠前的位置,就可以提高效率。likely(condition)表示 condition 这个条件是大概率为真的,即程序流大概率会走到这个分支。unlikely(condition)表示 condition 这个条件是大概率为假的,即程序流大概率不会走到这个分支。如下图是一个例子:

access_ok(addr, size)函数可用于检查用户空间指针是否可用,其中addr为用户空间的指针变量,指向一个要检查的内存块的开始,size是要检查的内存块的大小,如果待检查用户空间的内存块可用该函数返回真,否则返回假。

13.内核驱动程序中添加调试信息的几种方法:

  • 使用printk函数进行打印
  • 使用dump_stack()函数:dump_stack() 会打印出当前执行栈的调用信息,显示从当前函数到栈顶的所有函数调用路径
  • 使用WARN(condition, fmt...) 和 WARN_ON(condition):这是Linux内核中的调试宏,主要用于在代码中进行条件检查,当某个条件不满足时,向内核日志输出警告信息,并可以触发调试处理。其中condition是要检查的条件,如果条件为真,宏会打印警告信息。fmt...为可变参数,用于格式化打印的消息,类似 printf 的格式。这两个宏的打印信息内容与dump_stack()函数类似。WARN_ON(condition)的返回值是true或false,具体取决于条件condition是否为真
  • 使用BUG()和BUG_ON(condition)函数:它们都是 Linux 内核中的调试宏,用于在遇到严重错误时触发内核的调试功能,主要目的是标识和报告致命的错误,并在发生错误时终止内核的执行。BUG() 宏用于在发生严重错误时立即触发内核崩溃,并生成一个内核 panic,它没有条件检查,因此它总是会执行,并且不会返回。BUG_ON(condition) 是一个带有条件检查的宏,用于在给定条件condition为真时触发内核崩溃。这两个宏会将寄存器、堆栈等内容都打印出来
  • 使用panic(fmt...)函数:用于在发生严重错误时触发内核崩溃,它输出一条格式化的错误信息,并终止内核的执行。panic() 的调用通常标志着程序进入了一个不可恢复的错误状态,系统会停止执行,并且可能会生成一个内核转储供后续分析

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

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

相关文章

2025年,电脑还需要分区吗?

随着2025年的到来&#xff0c;电脑存储空间已经不像以前那么金贵&#xff0c;固态硬盘&#xff08;SSD&#xff09;容量更大、速度更快&#xff0c;云存储也成了日常标配。许多人开始质疑&#xff1a;电脑还需要像以前那样分区吗&#xff1f; 一、分区到底是什么意思&#xff…

Springboot项目集成maven-assembly-plugin进行打包

通常我们将应用部署到服务器的某个目录下&#xff0c;一般情况下我们会提供像target&#xff08;存放应用jar包&#xff09;&#xff0c;bin&#xff08;项目启动/停止脚本&#xff09;&#xff0c;config&#xff08;项目配置文件&#xff09;&#xff0c;logs&#xff08;项目…

鸿蒙NEXT项目实战-百得知识库01

代码仓地址&#xff0c;大家记得点个star IbestKnowTeach: 百得知识库基于鸿蒙NEXT稳定版实现的一款企业级开发项目案例。 本案例涉及到多个鸿蒙相关技术知识点&#xff1a; 1、布局 2、配置文件 3、组件的封装和使用 4、路由的使用 5、请求响应拦截器的封装 6、位置服务 7、三…

【DeepSeek应用】本地部署deepseek模型后,如何在vscode中调用该模型进行代码撰写,检视和优化?

若已成功在本地部署了 DeepSeek 模型(例如通过 vscode-llm、ollama 或私有 API 服务),在 VS Code 中调用本地模型进行代码撰写、检视和优化的完整流程如下: 1. 准备工作:确认本地模型服务状态 模型服务类型: 若使用 HTTP API 服务(如 FastAPI/Flask 封装),假设服务地址…

jenkins 配置邮件问题整理

版本&#xff1a;Jenkins 2.492.1 插件&#xff1a; A.jenkins自带的&#xff0c; B.安装功能强大的插件 配置流程&#xff1a; 1. jenkins->系统配置->Jenkins Location 此处的”系统管理员邮件地址“&#xff0c;是配置之后发件人的email。 2.配置系统自带的邮件A…

Android Coil3阶梯preload批量Bitmap拼接扁平宽图,Kotlin

Android Coil3阶梯preload批量Bitmap拼接扁平宽图&#xff0c;Kotlin <uses-permission android:name"android.permission.WRITE_EXTERNAL_STORAGE" /><uses-permission android:name"android.permission.READ_EXTERNAL_STORAGE" /><uses-p…

C++基础 [八] - list的使用与模拟实现

目录 list的介绍 List的迭代器失效问题 List中sort的效率测试 list 容器的模拟实现思想 模块分析 作用分析 list_node类设计 list 的迭代器类设计 迭代器类--存在的意义 迭代器类--模拟实现 模板参数 和 成员变量 构造函数 * 运算符的重载 运算符的重载 -- 运…

【系统架构设计师】操作系统 - 特殊操作系统 ③ ( 微内核操作系统 | 单体内核 操作系统 | 内核态 | 用户态 | 单体内核 与 微内核 对比 )

文章目录 一、微内核操作系统1、单体内核 操作系统2、微内核操作系统 引入3、微内核操作系统 概念4、微内核操作系统 案例 二、单体内核 与 微内核 对比1、功能对比2、单体内核 优缺点3、微内核 优缺点 一、微内核操作系统 1、单体内核 操作系统 单体内核 操作系统 工作状态 : …

系统思考:恶性循环

去年&#xff0c;我给一家知名人力资源公司交付了两个项目——一个在6月&#xff0c;另一个在8月&#xff0c;至今半年多了依然没有收到课酬。催促多次&#xff0c;得到的答复却各式各样&#xff1a;销售说老板卡了额度&#xff0c;老板说具体情况还需了解。每一次的推诿&#…

基于springboot的房屋租赁系统(008)

摘 要 社会的发展和科学技术的进步&#xff0c;互联网技术越来越受欢迎。网络计算机的生活方式逐渐受到广大人民群众的喜爱&#xff0c;也逐渐进入了每个用户的使用。互联网具有便利性&#xff0c;速度快&#xff0c;效率高&#xff0c;成本低等优点。 因此&#xff0c;构建符…

视频翻译器免费哪个好?轻松玩转视频直播翻译

你是不是觉得看外语视频很麻烦&#xff1f;每次遇到喜欢的外语电影、电视剧或动漫&#xff0c;总是要等字幕组的翻译&#xff0c;或者因为语言不通而错过精彩的情节。 这个时候&#xff0c;掌握多语种直播翻译方案就显得尤为重要&#xff0c;有了实时字幕&#xff0c;看外语视…

在cherry studio中使用MCP——本地文件管理FileSystem

cherry studio是一款开源的AI助手工具&#xff0c;可以便捷地利用API访问各种LLM&#xff0c;有关cherry studio的使用这里不再多说&#xff0c;可以参考这篇文章https://blog.csdn.net/m0_65494437/article/details/145478823 官网&#xff1a;https://cherry-ai.com/ MCP是什…

c++类和对象(下篇)下

下面就来补充一下c雷和对象最后一点内容. 首先先补充一下上一篇博客上c类和对象(下篇)上-CSDN博客最后学习的静态成员变量的小练习求123...n_牛客题霸_牛客网 (nowcoder.com)下面就是题解.灵活的运用了静态成员变量不销毁的特点,建立数组利用构造函数来完成n次相加. class A{ …

《TCP/IP网络编程》学习笔记 | Chapter 19:Windows 平台下线程的使用

《TCP/IP网络编程》学习笔记 | Chapter 19&#xff1a;Windows 平台下线程的使用 《TCP/IP网络编程》学习笔记 | Chapter 19&#xff1a;Windows 平台下线程的使用内核对象内核对象的定义内核对象归操作系统所有 基于 Windows 的线程创建进程与线程的关系Windows 中线程的创建方…

docker需要sudo才能使用

一种方法是添加当前用户到docker组里去&#xff0c;当时添加的时候貌似是没问题的&#xff0c;但是现在又不可以了 产生的报错 ❯ docker images Cannot connect to the Docker daemon at unix:///home/ying/.docker/desktop/docker.sock. Is the docker daemon running?解决…

学习记录 6 pointnet复现

一、复现代码 然后去找相关的2d的声呐图像分类的算法 融合可以搞的&#xff0c;虽然有文献但是不多&#xff0c;感觉也是可以的 """ Author: Benny Date: Nov 2019 """import os import sys import torch import numpy as npimport datetime …

Linux 文件操作-标准IO函数3- fread读取、fwrite写入、 fprintf向文件写入格式化数据、fscanf逐行读取格式化数据的验证

目录 1. fread 从文件中读取数据 1.1 读取次数 每次读取字节数 < 原内容字节数 1.2 读取次数 每次读取字节数 > 原内容字节数 2.fwrite 向文件中写入数据 2.1写入字符串验证 2.2写入结构体验证 3. fprintf 将数据写入到指定文件 4. fscanf 从文件中逐行读取内容…

Python 中下划线 “_” 的多面性:从变量到约定

# Python中下划线“_”的多面性&#xff1a;从变量到约定 在Python的语法体系里&#xff0c;下划线“_”看似毫不起眼&#xff0c;实则扮演着极为重要且多样化的角色。它不仅能作为普通变量参与编程&#xff0c;更在多个特殊场景下有着独特的用途与约定。深入理解下划线的各种…

深入 Linux 声卡驱动开发:核心问题与实战解析

1. 字符设备驱动如何为声卡提供操作接口&#xff1f; 问题背景 在 Linux 系统中&#xff0c;声卡被抽象为字符设备。如何通过代码让应用程序能够访问声卡的录音和播放功能&#xff1f; 核心答案 1.1 字符设备驱动的核心结构 Linux 字符设备驱动通过 file_operations 结构体定…

基于Spring Boot的图书管理系统的设计与实现(LW+源码+讲解)

专注于大学生项目实战开发,讲解,毕业答疑辅导&#xff0c;欢迎高校老师/同行前辈交流合作✌。 技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、小程序、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容&#xff1a;…