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

用户态到内核态:Linux信号传递的九重门(二)

1. 保存信号

1.1. 信号其他相关常见概念

  • 实际执⾏信号的处理动作称为信号递达(Delivery)。
  • 信号从产⽣到递达之间的状态,称为信号未决(Pending)。
  • 进程可以选择阻塞 (Block )某个信号。
  • 被阻塞的信号产⽣时将保持在未决状态,直到进程解除对此信号的阻塞,才执⾏递达的动作。

1.2. 在内核中的表示

 信号在内核中的表⽰意图

  • 每个信号都有两个标志位分别表⽰阻塞(block)和未决(pending),还有⼀个函数指针表⽰处理动作。信号产⽣时,内核在进程控制块中设置该信号的未决标志,直到信号递达才清除该标志。在上图的例⼦中,SIGHUP信号未阻塞也未产⽣过,当它递达时执⾏默认处理动作。
  • SIGINT信号产⽣过,但正在被阻塞,所以暂时不能递达。虽然它的处理动作是忽略,但在没有解除阻塞之前不能忽略这个信号,因为进程仍有机会改变处理动作之后再解除阻塞。
  • SIGQUIT信号未产⽣过,⼀旦产⽣SIGQUIT信号将被阻塞,它的处理动作是⽤⼾⾃定义函数sighandler。
// 内核结构 2.6.18
struct task_struct
{/* signal handlers */struct sighand_struct *sighand;sigset_t blocked struct sigpending pending;
};struct sighand_struct
{atomic_t count;struct k_sigaction action[_NSIG]; // #define _NSIG 64spinlock_t siglock;
};struct __new_sigaction
{__sighandler_t sa_handler;unsigned long sa_flags;void (*sa_restorer)(void); /* Not used by Linux/SPARC */__new_sigset_t sa_mask;
};struct k_sigaction
{struct __new_sigaction sa;void __user *ka_restorer;
};/* Type of a signal handler. */
typedef void (*__sighandler_t)(int);
struct sigpending
{struct list_head list;sigset_t signal;
};

1.3. sigset_t

从上图来看,每个信号只有⼀个bit的未决标志, ⾮0即1, 不记录该信号产⽣了多少次,阻塞标志也是这样表⽰的。因此, 未决和阻塞标志可以⽤相同的数据类型sigset_t来存储, , 这个类型可以表⽰每个信号的“有效”或“⽆效”状态, 在阻塞信号集中“有效”和“⽆效”的含义是该信号是否被阻塞, ⽽在未决信号集中“有效”和“⽆效”的含义是该信号是否处于未决状态。下⼀节将详细介绍信号集的各种操作。阻塞信号集也叫做当前进程的 这⾥的“屏蔽”应该理解为阻塞⽽不是忽略。

1.4. 信号集操作函数

sigset_t类型对于每种信号⽤⼀个bit表⽰“有效”或“⽆效”状态, ⾄于这个类型内部如何存储这些
bit则依赖于系统实现, 从使⽤者的⻆度是不必关⼼的, 使⽤者只能调⽤以下函数来操作sigset_ t变量,⽽不应该对它的内部数据做任何解释, ⽐如⽤printf直接打印sigset_t变量是没有意义的。
#include <signal.h>int sigemptyset(sigset_t *set);
int sigfillset(sigset_t *set);
int sigaddset(sigset_t *set, int signo);
int sigdelset(sigset_t *set, int signo);
int sigismember(const sigset_t *set, int signo);
  • 函数sigemptyset初始化set所指向的信号集,使其中所有信号的对应bit清零,表⽰该信号集不包含任何有效信号。
  • 函数sigfillset初始化set所指向的信号集,使其中所有信号的对应bit置位,表⽰ 该信号集的有效信号包括系统⽀持的所有信号。
  • 注意,在使⽤sigset_ t类型的变量之前,⼀定要调 ⽤sigemptyset或sigfillset做初始化,使信号集处于确定的状态。初始化sigset_t变量之后就可以在调⽤sigaddset和sigdelset在该信号集中添加或删除某种有效信号。

这四个函数都是成功返回0,出错返回-1。sigismember是⼀个布尔函数,⽤于判断⼀个信号集的有效信号中是否包含 某种信号,若包含则返回1,不包含则返回0,出错返回-1。

1.4.1. sigprocmask

调⽤函数 sigprocmask 可以读取或更改进程的信号屏蔽字(阻塞信号集)。
#include <signal.h>
int sigprocmask(int how, const sigset_t *set, sigset_t *oset);返回值:若成功则为0,若出错则为-1
如果oset是⾮空指针,则读取进程的当前信号屏蔽字通过oset参数传出。如果set是⾮空指针,则更改
进程的信号屏蔽字,参数how指⽰如何更改。如果oset和set都是⾮空指针,则先将原来的信号屏蔽字备份到oset⾥,然后 根据set和how参数更改信号屏蔽字。假设当前的信号屏蔽字为mask,下表说明了how参数的可选值。
如果调⽤sigprocmask解除了对当前若⼲个未决信号的阻塞,则在sigprocmask返回前,⾄少将其中⼀
个信号递达。

1.4.2. sigpending

#include <signal.h>
int sigpending(sigset_t *set);读取当前进程的未决信号集,通过set参数传出。
调⽤成功则返回0,出错则返回-1

1.5. 测试相关函数

测试代码:

#include <iostream>
#include <unistd.h>
#include <cstdio>
#include <sys/types.h>
#include <sys/wait.h>void Printpending(const sigset_t &pending)
{std::cout << "curr process[" << getpid() << "]pending";for (int i = 31; i >= 1; i--){if (sigismember(&pending, i) == 1){std::cout << "1";}else{std::cout << "0";}}std::cout<<std::endl;
}void handler(int signum)
{std::cout << "第" << signum << "号信号被递达!" << std::endl;std::cout << "------------------------------------" << std::endl;sigset_t pending;Printpending(pending);std::cout << "------------------------------------" << std::endl;
}int main()
{// Step1. 捕捉2号信号signal(2, handler);// Step2. 屏蔽2号信号sigset_t old_set, set;// 只是把用户级别的sigset_t置空,内核block没有置空。sigemptyset(&old_set);sigemptyset(&set);sigaddset(&set, 2);int ret = sigprocmask(SIG_BLOCK, &set, &old_set);int cnt = 15;while (true){sigset_t pending;sigpending(&pending);cnt--;Printpending(pending);if (cnt == 0){std::cout << "解除对2号信号的屏蔽!!!" << std::endl;sigprocmask(SIG_SETMASK, &old_set, &set);}sleep(1);}return 0;
}

测试结果:

2. 捕捉信号

2.1. 信号捕捉的流程

 如果信号的处理动作是⽤⼾⾃定义函数,在信号递达时就调⽤这个函数,这称为捕捉信号。

 由于信号处理函数的代码是在⽤⼾空间的,处理过程⽐较复杂,举例如下:

  • ⽤⼾程序注册了 SIGQUIT 信号的处理函数 sighandler
  • 当前正在执⾏ main 函数,这时发⽣中断或异常切换到内核态。
  • 在中断处理完毕后要返回⽤⼾态的 main 函数之前检查到有信号 SIGQUIT 递达。
  • 内核决定返回⽤⼾态后不是恢复 main 函数的上下⽂继续执⾏,⽽是执⾏ sighandler
    数, sighandler main 函数使⽤不同的堆栈空间,它们之间不存在调⽤和被调⽤的关系,是两个独⽴的控制流程。
  • ​​​​​​sighandler 函数返回后⾃动执⾏特殊的系统调⽤ sigreturn 再次进⼊内核态。
  • 如果没有新的信号要递达,这次再返回⽤⼾态就是恢复 main 函数的上下⽂继续执⾏了。

 2.2. sigaction

#include <signal.h>
int sigaction(int signo, const struct sigaction *act, struct sigaction *oact);
  • sigaction函数可以读取和修改与指定信号相关联的处理动作。调⽤成功则返回0,出错则返回- 1。signo是指定信号的编号。若act指针⾮空,则根据act修改该信号的处理动作。若oact指针⾮空, 则通过oact传出该信号原来的处理动作。act和oact指向sigaction结构体
  • 将sa_handler赋值为常数SIG_IGN传给sigaction表⽰忽略信号,赋值为常数SIG_DFL表⽰执⾏系统默认动作,赋值为⼀个函数指针表⽰⽤⾃定义函数捕捉信号,或者说向内核注册了⼀个信号处理函数,该函数返回值为void,可以带⼀个int参数,通过参数可以得知当前信号的编号,这样就可以⽤同⼀个函数处理多种信号。显然,这也是⼀个回调函数,不是被main函数调⽤,⽽是被系统所调⽤。

当某个信号的处理函数被调⽤时,内核⾃动将当前信号加⼊进程的信号屏蔽字,当信号处理函数返回时⾃动恢复原来的信号屏蔽字,这样就保证了在处理某个信号时,如果这种信号再次产⽣,那么 它会被阻塞到当前处理结束为⽌。 如果在调⽤信号处理函数时,除了当前信号被⾃动屏蔽之外,还希望⾃动屏蔽另外⼀些信号,则⽤sa_mask字段说明这些需要额外屏蔽的信号,当信号处理函数返回时⾃动恢复原来的信号屏蔽字。

2.3. OS是怎么运行的

2.3.1. 硬件中断

  • 操作系统自己维护了一张中断向量表,用于处理各种中断。中断向量表属于操作系统的一部分,启动的时候就加载到内存之中了。
  •  通过外部硬件中断,操作系统就不需要对外设进⾏任何周期性的检测或者轮询。
  • 由外部设备触发的,中断系统运⾏流程,叫做硬件中断。
// Linux内核0.11源码
void trap_init(void)
{int i;set_trap_gate(0, &divide_error); // 设置除操作出错的中断向量值。以下雷同。set_trap_gate(1, &debug);set_trap_gate(2, &nmi);set_system_gate(3, &int3); /* int3-5 can be called from all */set_system_gate(4, &overflow);set_system_gate(5, &bounds);set_trap_gate(6, &invalid_op);set_trap_gate(7, &device_not_availab);// Linux内核0.11源码void trap_init(void){int i;set_trap_gate(0, &divide_error); // 设置除操作出错的中断向量值。以下雷同。set_trap_gate(1, &debug);set_trap_gate(2, &nmi);set_system_gate(3, &int3); /* int3-5 can be called from all */set_system_gate(4, &overflow);set_system_gate(5, &bounds);set_trap_gate(6, &invalid_op);set_trap_gate(7, &device_not_availab);}for (i = 17; i < 48; i++)set_trap_gate(i, &reserved);set_trap_gate(45, &irq13);              // 设置协处理器的陷阱⻔。outb_p(inb_p(0x21) & 0xfb, 0x21);       // 允许主8259A 芯⽚的IRQ2 中断请求。outb(inb_p(0xA1) & 0xdf, 0xA1);         // 允许从8259A 芯⽚的IRQ13 中断请求。set_trap_gate(39, &parallel_interrupt); // 设置并⾏⼝的陷阱⻔。
}void rs_init(void)
{set_intr_gate(0x24, rs1_interrupt); // 设置串⾏⼝1 的中断⻔向量(硬件IRQ4 信号)。set_intr_gate(0x23, rs2_interrupt); // 设置串⾏⼝2 的中断⻔向量(硬件IRQ3 信号)。init(tty_table[1].read_q.data);     // 初始化串⾏⼝1(.data 是端⼝号)。init(tty_table[2].read_q.data);     // 初始化串⾏⼝2。outb(inb_p(0x21) & 0xE7, 0x21);     // 允许主8259A 芯⽚的IRQ3,IRQ4 中断信号请求。
}

 2.3.2. 时钟中断

操作系统在硬件的推动下,自动调度。

// Linux 内核0.11
// main.c
sched_init(); // 调度程序初始化(加载了任务0 的tr, ldtr) (kernel/sched.c)
// 调度程序的初始化⼦程序。
void sched_init(void)
{... set_intr_gate(0x20, &timer_interrupt);// 修改中断控制器屏蔽码,允许时钟中断。outb(inb_p(0x21) & ~0x01, 0x21);// 设置系统调⽤中断⻔。set_system_gate(0x80, &system_call);...
}
// system_call.s
_timer_interrupt : ...; // do_timer(CPL)执⾏任务切换、计时等⼯作,在kernel/shched.c,305 ⾏实现。
call _do_timer;         // 'do_timer(long CPL)' does everything from
// 调度⼊⼝
void do_timer(long cpl)
{... schedule();
}
void schedule(void)
{... switch_to(next); // 切换到任务号为next 的任务,并运⾏之。
}

2.3.3. 死循环

我们可以将操作系统理解成一个死循环。

void main(void) /* 这⾥确实是void,并没错。 */
{ /* 在startup 程序(head.s)中就是这样假设的。 */.../** 注意!! 对于任何其它的任务,'pause()'将意味着我们必须等待收到⼀个信号才会返* 回就绪运⾏态,但任务0(task0)是唯⼀的意外情况(参⻅'schedule()'),因为任* 务0 在任何空闲时间⾥都会被激活(当没有其它任务在运⾏时),* 因此对于任务0'pause()'仅意味着我们返回来查看是否有其它任务可以运⾏,如果没* 有的话我们就回到这⾥,⼀直循环执⾏'pause()'。*/for (;;)pause();
} // end main

这样,操作系统,就在硬件时钟的推动下,进行自动调度。

2.3.4. 软中断

  • 上述外部硬件中断,需要硬件设备触发。
  • 为了让操作系统⽀持进⾏系统调⽤,CPU也设计了对应的汇编指令(int 或者 syscall),可以让CPU内部触发中断逻辑。(软中断)
    系统调用的过程 其实就是先int 0x80、syscall陷⼊内核,本质就是触发软中断,CPU就会⾃动执 ⾏系统调⽤的处理⽅法,⽽这个⽅法会根据系统调⽤号,⾃动查表,执⾏对应的⽅法。
系统调用号的本质就是数组下标!
// sys.h
// 系统调⽤函数指针表。⽤于系统调⽤中断处理程序(int 0x80),作为跳转表。
extern int sys_setup (); // 系统启动初始化设置函数。 (kernel/blk_drv/hd.c,71)
extern int sys_exit (); // 程序退出。 (kernel/exit.c, 137)
extern int sys_fork (); // 创建进程。 (kernel/system_call.s, 208)
extern int sys_read (); // 读⽂件。 (fs/read_write.c, 55)
extern int sys_write (); // 写⽂件。 (fs/read_write.c, 83)
extern int sys_open (); // 打开⽂件。 (fs/open.c, 138)
extern int sys_close (); // 关闭⽂件。 (fs/open.c, 192)
extern int sys_waitpid (); // 等待进程终⽌。 (kernel/exit.c, 142)
extern int sys_creat (); // 创建⽂件。 (fs/open.c, 187)
extern int sys_link (); // 创建⼀个⽂件的硬连接。 (fs/namei.c, 721)
extern int sys_unlink (); // 删除⼀个⽂件名(或删除⽂件)。 (fs/namei.c, 663)
extern int sys_execve (); // 执⾏程序。 (kernel/system_call.s, 200)
extern int sys_chdir (); // 更改当前⽬录。 (fs/open.c, 75)
extern int sys_time (); // 取当前时间。 (kernel/sys.c, 102)
extern int sys_mknod (); // 建⽴块/字符特殊⽂件。 (fs/namei.c, 412)
extern int sys_chmod (); // 修改⽂件属性。 (fs/open.c, 105)
extern int sys_chown (); // 修改⽂件宿主和所属组。 (fs/open.c, 121)
extern int sys_break (); // (-kernel/sys.c, 21)
extern int sys_stat (); // 使⽤路径名取⽂件的状态信息。 (fs/stat.c, 36)
extern int sys_lseek (); // 重新定位读/写⽂件偏移。 (fs/read_write.c, 25)
extern int sys_getpid (); // 取进程id。 (kernel/sched.c, 348)
extern int sys_mount (); // 安装⽂件系统。 (fs/super.c, 200)
extern int sys_umount (); // 卸载⽂件系统。 (fs/super.c, 167)
extern int sys_setuid (); // 设置进程⽤⼾id。 (kernel/sys.c, 143)
extern int sys_getuid (); // 取进程⽤⼾id。 (kernel/sched.c, 358)
extern int sys_stime (); // 设置系统时间⽇期。 (-kernel/sys.c, 148)
extern int sys_ptrace (); // 程序调试。 (-kernel/sys.c, 26)
extern int sys_alarm (); // 设置报警。 (kernel/sched.c, 338)
extern int sys_fstat (); // 使⽤⽂件句柄取⽂件的状态信息。(fs/stat.c, 47)
extern int sys_pause (); // 暂停进程运⾏。 (kernel/sched.c, 144)
extern int sys_utime (); // 改变⽂件的访问和修改时间。 (fs/open.c, 24)
extern int sys_stty (); // 修改终端⾏设置。 (-kernel/sys.c, 31)
extern int sys_gtty (); // 取终端⾏设置信息。 (-kernel/sys.c, 36)
extern int sys_access (); // 检查⽤⼾对⼀个⽂件的访问权限。(fs/open.c, 47)
extern int sys_nice (); // 设置进程执⾏优先权。 (kernel/sched.c, 378)
extern int sys_ftime (); // 取⽇期和时间。 (-kernel/sys.c,16)
extern int sys_sync (); // 同步⾼速缓冲与设备中数据。 (fs/buffer.c, 44)
extern int sys_kill (); // 终⽌⼀个进程。 (kernel/exit.c, 60)
extern int sys_rename (); // 更改⽂件名。 (-kernel/sys.c, 41)
extern int sys_mkdir (); // 创建⽬录。 (fs/namei.c, 463)
extern int sys_rmdir (); // 删除⽬录。 (fs/namei.c, 587)
extern int sys_dup (); // 复制⽂件句柄。 (fs/fcntl.c, 42)
extern int sys_pipe (); // 创建管道。 (fs/pipe.c, 71)
extern int sys_times (); // 取运⾏时间。 (kernel/sys.c, 156)
extern int sys_prof (); // 程序执⾏时间区域。 (-kernel/sys.c, 46)
extern int sys_brk (); // 修改数据段⻓度。 (kernel/sys.c, 168)
extern int sys_setgid (); // 设置进程组id。 (kernel/sys.c, 72)
extern int sys_getgid (); // 取进程组id。 (kernel/sched.c, 368)
extern int sys_signal (); // 信号处理。 (kernel/signal.c, 48)
extern int sys_geteuid (); // 取进程有效⽤⼾id。 (kenrl/sched.c, 363)
extern int sys_getegid (); // 取进程有效组id。 (kenrl/sched.c, 373)
extern int sys_acct (); // 进程记帐。 (-kernel/sys.c, 77)
extern int sys_phys (); // (-kernel/sys.c, 82)
extern int sys_lock (); // (-kernel/sys.c, 87)
extern int sys_ioctl (); // 设备控制。 (fs/ioctl.c, 30)
extern int sys_fcntl (); // ⽂件句柄操作。 (fs/fcntl.c, 47)
extern int sys_mpx (); // (-kernel/sys.c, 92)
extern int sys_setpgid (); // 设置进程组id。 (kernel/sys.c, 181)
extern int sys_ulimit (); // (-kernel/sys.c, 97)
extern int sys_uname (); // 显⽰系统信息。 (kernel/sys.c, 216)
extern int sys_umask (); // 取默认⽂件创建属性码。 (kernel/sys.c, 230)
extern int sys_chroot (); // 改变根系统。 (fs/open.c, 90)
extern int sys_ustat (); // 取⽂件系统信息。 (fs/open.c, 19)
extern int sys_dup2 (); // 复制⽂件句柄。 (fs/fcntl.c, 36)
extern int sys_getppid (); // 取⽗进程id。 (kernel/sched.c, 353)
extern int sys_getpgrp (); // 取进程组id,等于getpgid(0)。(kernel/sys.c, 201)
extern int sys_setsid (); // 在新会话中运⾏程序。 (kernel/sys.c, 206)
extern int sys_sigaction (); // 改变信号处理过程。 (kernel/signal.c, 63)
extern int sys_sgetmask (); // 取信号屏蔽码。 (kernel/signal.c, 15)
extern int sys_ssetmask (); // 设置信号屏蔽码。 (kernel/signal.c, 20)
extern int sys_setreuid (); // 设置真实与/或有效⽤⼾id。 (kernel/sys.c,118)
extern int sys_setregid (); // 设置真实与/或有效组id。 (kernel/sys.c, 51)// 系统调⽤函数指针表。⽤于系统调⽤中断处理程序(int 0x80),作为跳转表。
fn_ptr sys_call_table[] = { sys_setup, sys_exit, sys_fork, sys_read,sys_write, sys_open, sys_close, sys_waitpid, sys_creat, sys_link,sys_unlink, sys_execve, sys_chdir, sys_time, sys_mknod, sys_chmod,sys_chown, sys_break, sys_stat, sys_lseek, sys_getpid, sys_mount,sys_umount, sys_setuid, sys_getuid, sys_stime, sys_ptrace, sys_alarm,sys_fstat, sys_pause, sys_utime, sys_stty, sys_gtty, sys_access,sys_nice, sys_ftime, sys_sync, sys_kill, sys_rename, sys_mkdir,sys_rmdir, sys_dup, sys_pipe, sys_times, sys_prof, sys_brk, sys_setgid,sys_getgid, sys_signal, sys_geteuid, sys_getegid, sys_acct, sys_phys,sys_lock, sys_ioctl, sys_fcntl, sys_mpx, sys_setpgid, sys_ulimit,sys_uname, sys_umask, sys_chroot, sys_ustat, sys_dup2, sys_getppid,sys_getpgrp, sys_setsid, sys_sigaction, sys_sgetmask, sys_ssetmask,sys_setreuid, sys_setregid
};

我们平时写代码的时候用系统调用,并不会直接在用户层使用int 0x80或者syscall因为Linux的gnu C标准库,给我们把⼏乎所有的系统调⽤全部封装了。

2.3.5. 缺页中断,除0错误,野指针错误,内存碎片处理

void trap_init(void)
{int i;set_trap_gate(0,&divide_error);// 设置除操作出错的中断向量值。以下雷同。set_trap_gate(1,&debug);set_trap_gate(2,&nmi);set_system_gate(3,&int3); /* int3-5 can be called from all */set_system_gate(4,&overflow);set_system_gate(5,&bounds);set_trap_gate(6,&invalid_op);set_trap_gate(7,&device_not_available);set_trap_gate(8,&double_fault);set_trap_gate(9,&coprocessor_segment_overrun);set_trap_gate(10,&invalid_TSS);set_trap_gate(11,&segment_not_present);set_trap_gate(12,&stack_segment);set_trap_gate(13,&general_protection);set_trap_gate(14,&page_fault);set_trap_gate(15,&reserved);set_trap_gate(16,&coprocessor_error);// 下⾯将int17-48 的陷阱⻔先均设置为reserved,以后每个硬件初始化时会重新设置⾃⼰的陷阱⻔。for (i=17;i<48;i++)set_trap_gate(i,&reserved);set_trap_gate(45,&irq13);// 设置协处理器的陷阱⻔。outb_p(inb_p(0x21)&0xfb,0x21);// 允许主8259A 芯⽚的IRQ2 中断请求。outb(inb_p(0xA1)&0xdf,0xA1);// 允许从8259A 芯⽚的IRQ13 中断请求。set_trap_gate(39,&parallel_interrupt);// 设置并⾏⼝的陷阱⻔。
}
缺⻚中断?内存碎⽚处理?除零野指针错误?这些问题,全部都会被转换成为CPU内部的软中断,
然后⾛中断处理例程,完成所有处理。有的是进⾏申请内存,填充⻚表,进⾏映射的。有的是⽤来
处理内存碎⽚的,有的是⽤来给⽬标进⾏发送信号,杀掉进程等等。

2.4. 如何理解用户态和内核态

  • 操作系统⽆论怎么切换进程,都能找到同⼀个操作系统!换句话说操作系统系统调⽤⽅法的执⾏,是在进程的地址空间中执⾏的
  • ⽤⼾态就是执⾏⽤⼾[0,3]GB时所处的状态
  • 内核态就是执⾏内核[3,4]GB时所处的状态
  • 区分就是按照CPU内的CPL决定,CPL的全称是Current Privilege Level,即当前特权级别。(用户态的权限为:11,内核态的权限为:00)
  • ⼀般执⾏ int 0x80 或者 syscall 软中断,CPL会在校验之后⾃动变更。

相关文章:

用户态到内核态:Linux信号传递的九重门(二)

1. 保存信号 1.1. 信号其他相关常见概念 实际执⾏信号的处理动作称为信号递达(Delivery)。 信号从产⽣到递达之间的状态,称为信号未决(Pending)。 进程可以选择阻塞 (Block )某个信号。 被阻塞的信号产⽣时将保持在未决状态,直到进程解除对此信号的阻塞,才执⾏递达的动作。 1.…...

【深度学习-Day 9】机器学习核心概念入门:监督、无监督与强化学习全解析

Langchain系列文章目录 01-玩转LangChain&#xff1a;从模型调用到Prompt模板与输出解析的完整指南 02-玩转 LangChain Memory 模块&#xff1a;四种记忆类型详解及应用场景全覆盖 03-全面掌握 LangChain&#xff1a;从核心链条构建到动态任务分配的实战指南 04-玩转 LangChai…...

android特许权限调试

新aosp中新应用无权限&#xff0c;但需要正常运行&#xff0c;来排查权限问题 ro.control_privapp_permissionslog这样做可确保设备保持工作状态&#xff0c;同时仍然提供违规行为列表。错误消息格式如下&#xff1a; PackageManager: Privileged permission {PERMISSION_NAM…...

如何避免Java中的ConcurrentModificationException

引言 在Java开发中&#xff0c;操作集合&#xff08;如List、Set、Map&#xff09;时&#xff0c;许多开发者都遇到过ConcurrentModificationException。这个异常通常出现在遍历集合的同时尝试修改其结构&#xff08;如添加或删除元素&#xff09;。本文将深入探讨这一异常的根…...

5月12日复盘-RNN

5月12日复盘 二、RNN 模型 1.先导 1.1 为什么需要循环神经网络 RNN ​ 上图是一幅全连接神经网络图&#xff0c;我们可以看到输入层-隐藏层-输出层&#xff0c;他们每一层之间是相互独立地&#xff0c;(框框里面代表同一层)&#xff0c;每一次输入生成一个节点&#xff0c;同…...

linux小主机搭建自己的nas(二)docker卸载navidrome

测试的时候安装了一个音乐播放器在root下面&#xff0c;现在先给他删掉 停止并删除容器 docker ps -a | grep navidrome# 停止并删除容器&#xff08;替换 YOUR_CONTAINER_NAME 为实际名称&#xff09; docker stop YOUR_CONTAINER_NAME && docker rm YOUR_CONTAINER…...

.NET 在鸿蒙系统上的适配现状

目录 .NET 在鸿蒙系统上的适配现状 鸿蒙系统对虚拟机的限制与.NET的适配挑战 NativeAOT 在鸿蒙系统中的适配原理与实现方式 已知问题与解决方案&#xff1a;鸿蒙系统中的 syscall 限制 鸿蒙系统适配中的技术难点与解决方案 跨平台编译的挑战与应对策略 依赖库管理与兼容…...

01-centos离线升级至almalinux

官网链接官方代码调整&#xff1a; 1. vi repositories/system_upgrade/common/actors/targetuserspacecreator/libraries/userspacegen.py with mounting.BindMount(sourceuserspace_dir, targetos.path.join(context.base_dir, install_root_dir.lstrip(/))):_restore_persi…...

Python 处理图像并生成 JSONL 元数据文件 - 固定text版本

Python 处理图像并生成 JSONL 元数据文件 - 固定text版本 flyfish JSONL&#xff08;JSON Lines&#xff09;简介 JSONL&#xff08;JSON Lines&#xff0c;也称为 newline-delimited JSON&#xff09;是一种轻量级的数据序列化格式&#xff0c;由一系列独立的 JSON 对象组成…...

uniapp使用npm下载

uniapp的项目在使用HBuilder X创建时是不会有node_modules文件夹的&#xff0c;如下图所示&#xff1a; 但是uni-app不管基于哪个框架&#xff0c;它内部一定是有node.js的&#xff0c;否则没有办法去实现框架层面的一些东西&#xff0c;只是说它略微有点差异。具体差异表现在…...

前端面试每日三题 - Day 31

这是我为准备前端/全栈开发工程师面试整理的第30天每日三题练习&#xff1a; ✅ 题目1&#xff1a;WebAssembly前端深度实践指南 核心优势对比 维度JavaScriptWebAssembly解析速度需要解析编译预编译二进制执行性能动态类型较慢静态类型接近原生内存管理自动垃圾回收手动内存…...

通义千问席卷日本!开源界“卷王”阿里通义千问成为日本AI发展新基石

据日本经济新闻&#xff08;NIKKEI&#xff09;报道&#xff0c;通义千问已成为日本AI开发的新基础&#xff0c;其影响力正逐步扩大&#xff0c;深刻改变着日本AI产业的格局。 同时&#xff0c;日本经济新闻将通义千问Qwen2.5-Max列为全球AI模型综合评测第六名&#xff0c;不仅…...

01 安装CANoe

文章目录 0、Introduction1、Install CANoe1.1、Unlock Package1.2、Kick autorun1.3、Install CANoe1.4、Wait Download1.5、Restart application1.6、Vector CANoe Installation1.7、Installation Successfully1.8、Open CANoe 2、Install Drivers2.1、Unlock Package2.2、Ki…...

AutoDL租用服务器教程

在跑ai模型的时候&#xff0c;容易遇到算力不够的情况。此时便需要租用服务器。autodl是个较为便宜的服务器租用平台&#xff0c;h20仅需七点几元每小时。下面是简单的介绍。 打开网站AutoDL算力云 | 弹性、好用、省钱。租GPU就上AutoDL&#xff0c;并登录账号 登录后&#xff…...

【人工智能-agent】--Dify中MCP工具存数据到MySQL

本文记录的工作如下&#xff1a; 自定义MCP工具&#xff0c;爬取我的钢铁网数据爬取的数据插值处理自定义MCP工具&#xff0c;把爬取到的数据&#xff08;str&#xff09;存入本地excel表格中自定义MCP工具&#xff0c;把爬取到的数据&#xff08;str&#xff09;存入本地MySQ…...

ctfshow——web入门351~356

SSRF没有出网的部分 web入门351 $ch curl_init($url); 作用&#xff1a;初始化一个 cURL 会话&#xff0c;并设置目标 URL。解释&#xff1a; curl_init($url) 创建一个新的 cURL 资源&#xff0c;并将其与 $url 关联。这里的 $url 是用户提供的&#xff0c;因此目标地址完全…...

堆复习(C语言版)

目录 1.树的相关概念&#xff1a; 2.堆的实现 3.TopK问题 4.总结 1.树的相关概念&#xff1a; 1.结点的度&#xff1a;一个结点含有的子树&#xff08;孩子&#xff09;个数。 A的度为6 2.叶结点or终端结点&#xff1a;度为0的结点。 J、K、L、H、I 都是叶子结点 3.非终端结…...

解决LangChain4j报错HTTP/1.1 header parser received no bytes

问题描述 当使用langchain4j-open-ai调用自己部署的大模型服务时报错&#xff1a; public static void main(String[] args) {OpenAiChatModel model OpenAiChatModel.builder().apiKey("none").modelName("qwen2.5-instruct").baseUrl("http://19…...

深入解析MySQL联合查询(UNION):案例与实战技巧

在数据库操作中&#xff0c;查询是最常用的操作之一。MySQL提供了强大的查询功能&#xff0c;联合查询&#xff08;UNION&#xff09;是其中非常有用的一项操作。联合查询可以将多个查询结果合并成一个结果集&#xff0c;使得从不同来源的数据整合变得更加简单高效。本文将详细…...

[计算机科学#14]:数据结构

【核知坊】&#xff1a;释放青春想象&#xff0c;码动全新视野。 我们希望使用精简的信息传达知识的骨架&#xff0c;启发创造者开启创造之路&#xff01;&#xff01;&#xff01; 内容摘要&#xff1a;数据结构是计算机科学中的核心概念&#xff0c;用于…...

【计算机网络】HTTP 协议

HTTP是什么&#xff1f; HTTP 全称是“超文本传输协议”&#xff0c;是互联网上应用最广泛的应用层协议&#xff0c;用于客户端和服务器之间的通信。 HTTP 的实现在 HTTP 3.0之前都是基于传输层的 TCP 实现的&#xff0c; HTTP 3.0 改为了基于 UDP 实现&#xff0c;但是现在市…...

原生的 XMLHttpRequest 和基于 jQuery 的 $.ajax 方法的异同之处以及使用场景

近期参与一个项目的开发&#xff0c;发现项目中的ajax请求有两种不同的写法&#xff0c;查询了下两种写法的异同之处以及使用场景。 下面将从以下两段简单代码进行异同之处的分析及使用场景的介绍&#xff1a; // 写法一&#xff1a; var xhr new XMLHttpRequest(); xhr.open…...

横向移动(上)

横向移动&#xff08;上&#xff09; 横向移动指的是攻击者在内网中获得初始访问权限之后&#xff0c;通过相关技术扩大敏感数据和高价值资产权限的行为 常见的横向移动的方式 1.通过web漏洞 2.通过远程桌面 3.通过账号密码 4.通过不安全的配置 5.通过系统漏洞 利用远控…...

关于 js:7. 模块化、构建与工具链

一、模块系统&#xff1a;CommonJS、ESM、UMD 模块系统的目标&#xff1a; 将代码拆分为独立的逻辑单元&#xff08;模块&#xff09;&#xff0c;实现封装、复用、依赖管理。 在 Web 前端/Node 中&#xff0c;因为 JavaScript 起初没有模块机制&#xff0c;因此出现了多个模…...

一次IPA被破解后的教训(附Ipa Guard等混淆工具实测)

一行代码的疏忽&#xff0c;一个默认的类名&#xff0c;一个未混淆的资源路径&#xff0c;都可能成为攻击者入侵的入口。 背景&#xff1a;一次“不值一提”的上线&#xff0c;成了代价惨重的经验 故事的起点很简单&#xff1a;我们给销售部门做了一款小型内部演示 App&#x…...

麒麟系统安装.net core环境变量

本文主要记录在麒麟系统上安装.net core的运行环境&#xff0c;这里使用的是麒麟V10桌面版&#xff0c;后续测试服务器到了之后再使用服务器版进行安装测试。 环境安装 下载 这里由于是桌面版&#xff0c;我直接使用浏览器下的包&#xff0c;下完之后在终端中安装。 安装 1…...

如何使用 React Hooks 替代类组件的生命周期方法?

文章目录 1. 引言2. useEffect 概述3. 模拟类组件的生命周期方法3.1 模拟 componentDidMount3.2 模拟 componentDidUpdate3.3 模拟 componentWillUnmount 4. 多个 useEffect 的使用5. 注意事项6. 总结 1. 引言 在 React 16.8 版本之前&#xff0c;开发者主要通过类组件&#x…...

windows 在安装 Ubuntu-20.04 显示操作超时解决办法

1. 问题概述与原因分析 在我们用下面命令安装 Ubuntu-20.04 时系统显示操作超时&#xff1a; wsl --install -d Ubuntu-20.04大概率是没打开 Windows 虚拟机监控程序平台&#xff0c;可以在控制面板–>程序和功能里面打开 2. 解决办法与步骤 解决方式如下&#xff1a; 我…...

Spring Boot中Redis序列化配置详解

精心整理了最新的面试资料和简历模板&#xff0c;有需要的可以自行获取 点击前往百度网盘获取 点击前往夸克网盘获取 引言 在使用Spring Boot集成Redis时&#xff0c;序列化方式的选择直接影响数据存储的效率和系统兼容性。默认的JDK序列化存在可读性差、存储空间大等问题&am…...

OpenCV进阶操作:光流估计

文章目录 前言一、光流估计1、光流估计是什么&#xff1f;2、光流估计的前提&#xff1f;1&#xff09;亮度恒定2&#xff09;小运动3&#xff09;空间一致 3、OpenCV中的经典光流算法1&#xff09;Lucas-Kanade方法&#xff08;稀疏光流&#xff09;2&#xff09; Farneback方…...

2025年渗透测试面试题总结-渗透测试红队面试八(题目+回答)

网络安全领域各种资源&#xff0c;学习文档&#xff0c;以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具&#xff0c;欢迎关注。 目录 渗透测试红队面试八 二百一十一、常见中间件解析漏洞利用方式 二百一十二、MySQL用户密码存储与加密 …...

前端面试高频50个问题,解答

以下是前端面试中常见的50个高频问题及其简要解答&#xff1a; HTML HTML5 有哪些新特性&#xff1f; 语义化标签&#xff08;如 <header>、<footer>&#xff09;、多媒体支持&#xff08;如 <audio>、<video>&#xff09;、本地存储&#xff08;如 l…...

Elasticsearch架构原理

1、Elasticsearch的节点类型 1.1 Master节点 在Elasticsearch启动时&#xff0c;会选举出来一个Master节点。当某个节点启动后&#xff0c;然后 使用Zen Discovery机制找到集群中的其他节点&#xff0c;并建立连接。 discovery.seed_hosts: ["192.168.21.130", &qu…...

前端面试宝典---webpack面试题

webpack 的 tree shaking 的原理 Webpack 的 Tree Shaking 过程主要包含以下步骤&#xff1a; 模块依赖分析&#xff1a;Webpack 首先构建一个完整的模块依赖图&#xff0c;确定每个模块之间的依赖关系。导出值分析&#xff1a;通过分析模块之间的 import 和 export&#xff…...

Vue 2 项目中配置 Tailwind CSS 和 Font Awesome 的最佳实践

Vue 2 项目中配置 Tailwind CSS 和 Font Awesome 的最佳实践 一、Tailwind CSS 配置 1. 安装依赖 npm install tailwindcssnpm:tailwindcss/postcss7-compat tailwindcss/postcss7-compat postcss^7 autoprefixer^92. 创建配置文件 npx tailwindcss init3. 创建样式文件 在…...

hiveserver2与beeline进行远程连接hive配置及遇到的问题

1、hiveserver2 参与用户模拟功能&#xff0c;因为开启后才能保证各用户之间的权限隔离。 1.1、配置 $HADOOP_HOME/etc/hadoop/core-site.xml <!--配置所有节点的root用户都可作为代理用户--> <property><name>hadoop.proxyuser.root.hosts</name>&…...

单词短语0512

当然可以&#xff0c;下面是“opportunity”在考研英语中的常用意思和高频短语&#xff0c;采用大字体展示&#xff0c;便于记忆&#xff1a; ✅ opportunity 的考研常用意思&#xff1a; &#x1f449; 机会&#xff0c;良机 表示有利的时机或条件&#xff0c;尤指成功的可能…...

c++刷题便捷函数(类似于stoi的小函数)

标题 stoi(字符串转整形)map和set都有count成员函数&#xff0c;返回值是该key的个数&#xff0c;可以用来查是否存在该元素。bool is_sorted(nums.begin(), nums.end() 检验是否有序INT_MAX,INT_MIN分别是整形最大和最小初始化二维矩阵 vector<vector\<int>> mart…...

想实现一个基于MCP的pptx生成系统架构图【初版实现】

技术栈:Python + MCP协议 + python-pptx + FastMCP 核心创新点:通过MCP协议实现PPTX元素的动态化生成与标准化模板管理 当前还是个半成品,后续持续更新。 主要先介绍一下思路。 一、MCP协议与系统设计原理 1.1 为什么选择MCP? 标准化工具调用:通过MCP将PPTX元素生成逻辑封…...

jwt学习

基于token的鉴权机制也是无状态的(类似于http协议)&#xff0c;不需要保在服务端保留用户的认证或会话信息。 构成 jwt由三部分构成&#xff1a;头部、payload、签名&#xff0c;中间用.隔开 头部(header) 包含两部分信息&#xff1a;声明类型、声明加密的算法 例如&#xff1a…...

pth的模型格式怎么变成SafeTensors了?

文章目录 背景传统模型格式的安全隐患效率与资源瓶颈跨框架兼容性限制Hugging Face 的解决方案&#xff1a;SafeTensors行业与社区的推动SafeTensors 的意义总结 背景 最近要找一些适合embedding的模型&#xff0c;在huggingface模型库上看到一些排名比较靠前的&#xff0c;准…...

如何判断IP是否被平台标记

一、基础检测&#xff1a;连通性与黑名单筛查 网络连通性测试 Ping与Traceroute&#xff1a;通过命令测试延迟和路由路径&#xff0c;若延迟>50ms或存在异常节点&#xff08;如某跳延迟>200ms&#xff09;&#xff0c;可能影响可用性。示例命令&#xff1a; bash ping 8.…...

【c++】异常详解

目录 C语言处理错误的局限性异常的定义异常的具体使用细则异常的抛出与捕获在函数调用链中异常栈展开匹配原则异常的重新抛出异常规范throw(类型)noexcept 成熟的异常体系c自己的异常体系异常的优缺点优点缺点 异常安全 C语言处理错误的局限性 C语言处理错误常常会用到assert和…...

从模型加密到授权交付,CodeMeter赋能3D打印商业化全流程

引言 在数字化制造快速演进的当下&#xff0c;3D 打印&#xff08;增材制造&#xff09;作为具备高度灵活性与创新潜力的制造方式&#xff0c;正重塑备件供应链与产品生命周期管理。然而&#xff0c;随着应用场景不断扩展&#xff0c;企业面临的知识产权保护、数字资产商业化与…...

ESP32开发之freeRTOS的事件组

什么是事件组事件组的应用场景事件组的API函数事件组应用举例总结什么是事件组 概念:事件组就是一个整数,高8位给内核使用,其他位用来表示事件。在ESP32的IDF freeRTOS中,这个整数是32位的,低24位用来供事件组使用。 举一个生活中的例子: 你在等快递,有三个包裹来自不…...

K8S中构建双架构镜像-从零到成功

背景介绍 公司一个客户的项目使用的全信创的环境&#xff0c;服务器采用arm64的机器&#xff0c;而我们的应用全部是amd64的&#xff0c;于是需要对现在公司流水线进行arm64版本的同步镜像生成。本文介绍从最开始到最终生成双架构的全部过程&#xff0c;以及其中使用的相关配置…...

腾讯怎样基于DeepSeek搭建企业应用?怎样私有化部署满血版DS?直播:腾讯云X DeepSeek!

2025新春&#xff0c;DeepSeek横空出世&#xff0c;震撼全球&#xff01; 通过算法优化&#xff0c;DeepSeek将训练与推理成本降低至国际同类模型的1/10&#xff0c;极大的降低了AI应用开发的门槛。 可以预见&#xff0c;2025年&#xff0c;是AI应用落地爆发之年&#xff01; ✔…...

【论信息系统项目的质量管理】

论信息系统项目的质量管理 前言一、抓好质量管理规划工作&#xff0c;为质量管理和确认提供指南和方向。二、做好管理质量相关工作&#xff0c;促进质量过程改进。三、抓好控制质量&#xff0c;确保实现质量目标四、综合协调质量与成本、进度、范围的关系总结 前言 为解决日常出…...

SpringAI框架中的RAG模块详解及应用示例

SpringAI框架中的RAG模块详解及应用示例 RAG&#xff08;Retrieval-Augmented Generation&#xff09;可以通过检索知识库&#xff0c;克服大模型训练完成后参数冻结的局限性&#xff0c;携带知识让大模型根据知识进行回答。SpringAI框架提供了模块化的API来支持RAG&#xff0…...

图像增强技术

一、目的 通过本实验加深对数字图像增强操作的理解&#xff0c;熟悉MATLAB中的有关函数&#xff1b;了解直方图均衡化和卷积滤波的原理&#xff1b;熟悉低通和高通滤波模板的构造方法。 二、实验内容与设计思想 1、观察实验结果可看出&#xff0c; 原图像 I的对比度较低&…...