Linux 理解进程信号

目录

一、共享内存通信机制中的临界资源访问与同步控制

1、概念

2、生活角度理解信号机制

3、信号量的操作

二、信号

1、生活角度的信号

2、技术应用角度的信号

3、操作系统角度的信号

信号如何产生

理解组合键变为信号

理解信号如何被进程保存

时钟中断(了解)

4、信号定义、kill -l查看信号列表

5、信号处理的常见方式


一、共享内存通信机制中的临界资源访问与同步控制

1、概念

基于对共享内存通信机制的理解,我们认识到要实现不同进程间的数据共享,关键是确保这些进程能够访问到同一份物理内存资源。在此之前,我们探讨的所有进程间通信手段,其核心目标都是确保进程间可以共享和访问同一份数据资源。

  1. 当这份资源被多个进程同时访问时,我们称其为“临界资源”,因为它的访问必须受到严格的控制,以避免竞争条件和数据不一致性问题。

  2. 在每个进程中,涉及访问临界资源的那段代码区域被称为“临界区”。临界区内的操作要求互斥执行,即在任意时刻,至多只有一个进程能够进入并执行这段代码。

  3. 为了保证进程间对临界资源的访问满足互斥性,我们需要采用适当的同步机制,确保在任何时候只有一个进程可以进入临界区进行操作。

#include <iostream>// 假设这是我们的临界资源:一个全局变量,它模拟一个打印机
int shared_resource = 0; // 全局计数器,一次只能有一个线程访问// 这是线程函数,其中访问和修改临界资源的代码段就是临界区
void thread_function(const char* name) {while (true) {// 简化版的“临界区入口”,在这里我们假设某种机制能够确保一次只有一个线程进入// (注:真实环境中,这将由互斥锁等同步原语来实现)// 开始临界区std::cout << name << " entered the critical section.\n";// 访问和修改临界资源shared_resource++;  // 假设这是打印一页纸的操作std::cout << "Page printed by " << name << ". Total pages: " << shared_resource << "\n";// 简化的“临界区出口”std::cout << name << " left the critical section.\n";// 模拟其他非临界区的工作// ...}
}int main() {// 假设有两个线程,分别模拟两个任务std::thread t1(thread_function, "Thread A");std::thread t2(thread_function, "Thread B");// 等待线程结束(在此处省略了join操作)return 0;
}

在这个例子中:

  • 临界资源shared_resource 是一个全局变量,代表着只能由一个线程同时访问和修改的资源,比如打印机的物理打印操作。

  • 临界区: 在 thread_function 函数中,打印输出 "entered the critical section." 到 "left the critical section." 之间的代码段就是临界区。在这个区域内,线程会访问和修改临界资源 shared_resource


原子性则是对这类操作性质的一种描述,它强调的是一个操作要么全部完成,要么完全不执行,不存在中间状态。

  • 在多执行流环境下,如果不加保护地同时访问临界资源,可能会导致数据竞争和不一致的情况发生。
  • 而在非临界区的代码执行,则不受这种互斥性的约束,多个执行流可以并行执行且彼此互不影响。
  • 简言之,正是由于对临界资源的不当访问,才引发了进程间通信中的同步问题,而通过实现互斥和保证原子性,我们可以有效地避免这些问题的发生。

2、生活角度理解信号机制

        在生活中,我们可以把信号机制比作去电影院观影时的座位预订系统。当你打算看电影时,并非径直走进影院就能随意落座。首先需要经历购票环节,这张电影票就像是一份承诺,代表着你有权在特定时间段内使用一个座位,即便此刻你并未实际坐在那里,座位已经被视为你的预定资源。

        对应到计算机,这一现象与进程试图进入临界区(即仅允许单个进程访问的资源区域)的过程十分相似。就如同电影院不会放任观众自行进入影厅抢占座位,操作系统也不会让进程未经许可就擅自访问临界资源。

        在此情境下,进程必须先通过某种方式取得“许可”——这个许可就是所谓的“信号量”。信号量的核心作用犹如现实中的电影票,当进程获取到一个有效的信号量时,这就意味着操作系统已经为该进程安排好对临界资源的使用权。只有持有信号量的进程才能安全地进入并操作临界资源,从而避免多个进程同时访问导致的数据冲突或不一致问题。

3、信号量的操作

 

信号量的操作基本可概括为以下几个步骤:

  1. 申请信号量:这是一个尝试进入临界区的过程。进程通过减少信号量的计数(如果信号量大于零)来标记对资源的请求。这等同于购买电影票,确认座位的预订。
  2. 访问临界资源:一旦信号量成功申请,进程就可以进入临界区执行其操作。这相当于拿着电影票进入放映厅,坐在自己预订的座位上。
  3. 释放信号量:进程完成其在临界区的操作后,会释放信号量,通常是通过增加信号量的计数来实现。这表明资源现在可以被其他进程预订,就如同观众观看完电影离开座位,座位可供下一位观众使用。

为了确保对临界资源的安全访问,我们需要使用信号量计数器来实现互斥和同步。申请信号量会导致计数器递减,释放信号量则会使计数器递增。P操作(申请信号量)和V操作(释放信号量)必须是原子的,以防止中间状态问题。

二、信号

1、生活角度的信号

在生活中,接收快递的过程与操作系统中处理信号的概念有异曲同工之处。想象一下,你在网购平台上购买了多个商品,就如同在系统中启动了多项任务,等待各自的“信号”——快递送达的通知。当快递员抵达楼下并向你发送送达通知时,这就相当于操作系统接收到一个“信号”。

在这个场景中,你可以做如下类比:

  1. 默认动作:当接收到“快递已到”的信号时,如果不做特别处理,默认的动作就像是立刻停下手头的事(如玩游戏),然后下楼签收包裹,之后拆开包裹并开始使用商品(如同进程接收到信号后执行默认操作,如进程终止或继续执行)。

  2. 自定义动作:如果对某个特殊商品(比如一盒零食)设置了特殊的“信号处理函数”,那么在接到通知后,你可能会选择暂时不立即取件,而是等一会儿,准备把它当作礼物送给女朋友,这就类似编程中设置自定义信号处理器函数,以便在接收到特定信号时执行定制化操作。

  3. 忽略快递:在收到快递到达的消息时,若你选择继续沉浸在游戏中而不去理会,这就类似于进程选择忽略某个信号,暂时不对该事件做出反应。

从接收到快递送达通知到实际下楼取件的过程,构成了一个类似操作系统中的“信号处理延时窗口”。在这个窗口期内,尽管你知道快递已到,但并不急于立即采取行动,而是根据自己的优先级和安排来调整处理时机。

整个过程体现了生活中的“异步处理”理念,因为快递送达的具体时间点具有不确定性,正如操作系统中的信号也可能随时到来一样。而如何应对这些“信号”,则完全取决于个人或进程事先设定的策略及实时情境判断。

2、技术应用角度的信号

[@localhost code_test]$ cat sig.c
#include <stdio.h>
int main()
{while (1) {printf("I am a process, I am waiting signal!\n");sleep(1);}
}
[@localhost code_test]$ . / sig
I am a process, I am waiting signal!
I am a process, I am waiting signal!
I am a process, I am waiting signal!
^ C
[@localhost code_test]$

在技术应用场景中,假设你网购下单购买了多件商品,正处于热切等待各商品快递送达的状态。就像上述C语言代码中的进程在持续循环等待信号一样,你清楚自己应该如何应对每一份即将到来的包裹。在实际生活中,快递员抵达你所在的楼宇时,你会通过某种方式得知快递已到达的通知。

  • 在计算机程序中,sig.c中的进程不断循环并输出“我正在等待信号!”,这象征着你在网购后持续关注物流动态的行为。sleep(1)则代表你间隔一定时间查询一次订单状态。
  • 当按下Ctrl-C时,就如同快递员送达包裹并触发了一次“中断通知”(硬件中断),操作系统接收到这个中断后将其解释为一个信号(如SIGINT),并将其发送给正在运行的前台进程(即等待信号的进程)。
  • 在现实生活中,当你收到快递员到达的通知后,可以选择立刻下楼取件或安排稍后处理。同样地,在计算机程序中,进程在接收到SIGINT信号后,默认会立即停止执行(退出进程),这就好比你收到快递通知后立即停止手头的事去收取包裹。
  • 不过,如果你希望在接收到信号后延时处理,就需要在程序中添加自定义的信号处理函数来模拟“稍后再取件”的逻辑。在示例代码中,按下Ctrl-C后进程直接结束,对应的就是立刻响应并结束等待信号的状态。

需要注意在计算机操作系统的环境中:

  1. 当你在终端中直接启动一个命令或程序时,默认情况下它将以前台进程的身份运行。这意味着,如果你按下了 Ctrl-C,产生的 SIGINT 信号将直接发送给当前处于前台的进程。若要在启动命令后使其在后台运行,只需在命令末尾添加一个 '&' 符号,这样一来,Shell 不必等待此进程结束即可接收新命令并启动其他进程。

  2. Shell 具有灵活的并发处理能力,它能同时管理一个前台进程及任意数量的后台进程。然而,值得注意的是,只有当前台进程才具备捕获由诸如 Ctrl-C 这类控制键触发产生的信号的能力。换句话说,后台进程无法直接响应来自终端的这类交互式信号。

  3. 对于前台进程中运行的用户空间代码而言,由于用户在进程执行的任何时刻都可能按下 Ctrl-C 发送 SIGINT 信号,因此进程在执行流程中的任何一个点都可能遭遇此信号并随之终止。这种不受特定执行阶段限制、随时可能出现的信号特性,使得信号对于进程的控制流程来说具有显著的异步性(Asynchronous)。这就意味着进程必须能够适时地响应这些非预期的外部事件,以保证其正常且稳定地运行。

3、操作系统角度的信号

信号如何产生

[@localhost code_test]$ cat sig.c
#include <stdio.h>
int main()
{while (1) {printf("I am a process, I am waiting signal!\n");sleep(1);}
}
[@localhost code_test]$ . / sig
I am a process, I am waiting signal!
I am a process, I am waiting signal!
I am a process, I am waiting signal!
^ C
[@localhost code_test]$
  • 当用户在终端中按下 Ctrl+C 组合键时,实际上触发了一个硬件中断。操作系统(OS)通过键盘设备驱动程序识别到这个特定的中断请求,并将其解释为向目标前台进程发送一个特定的信号——通常是编号为2的 SIGINT 信号。

  • 操作系统接收到组合键信号后,会遍历进程列表,定位到当前在终端前台运行的进程。一旦确定目标进程,OS就会在该进程的进程控制块(PCB)内部的数据结构中记录或更新相应的信号位图信息。

  • 信号位图通常是一个二进制的表示形式,例如,一个二进制位对应一个信号类型,当某位置1时就表示该进程已经收到了相应类型的信号。

理解组合键变为信号

  • 键盘通过中断机制与CPU通信,其中包含了对组合键(如Ctrl+C)的识别功能。当这样的组合键被按下时,硬件会触发一个中断请求,操作系统接收到这个中断后,经过一系列解析和处理步骤,将组合键的含义映射为特定的信号类型。

理解信号如何被进程保存

  • 每个进程在内核中都有一个进程控制块(PCB,Process Control Block),这是一个核心数据结构,用于存储和维护进程的状态信息,其中包括信号位图字段。当一个信号被发送给进程时,本质上是操作系统将这个信号的标记写入到该进程的PCB中的信号位图中。

  • “信号发送”的实质在于:操作系统不是通过某种通信机制发送信号,而是直接修改目标进程的PCB结构,改变其中信号位的状态,以此告知进程它已收到一个新的信号。进程随后可以通过检查其自身的PCB来得知收到了何种信号,并根据预先设定的策略进行相应的处理,如执行默认操作(如终止进程)、忽略信号或执行自定义的动作(如注册的信号处理器函数)。

[hbr@VM-16-9-centos signal]$ kill -l1) SIGHUP       2) SIGINT       3) SIGQUIT      4) SIGILL       5) SIGTRAP6) SIGABRT      7) SIGBUS       8) SIGFPE       9) SIGKILL     10) SIGUSR1
11) SIGSEGV     12) SIGUSR2     13) SIGPIPE     14) SIGALRM     15) SIGTERM
16) SIGSTKFLT   17) SIGCHLD     18) SIGCONT     19) SIGSTOP     20) SIGTSTP
21) SIGTTIN     22) SIGTTOU     23) SIGURG      24) SIGXCPU     25) SIGXFSZ
26) SIGVTALRM   27) SIGPROF     28) SIGWINCH    29) SIGIO       30) SIGPWR
31) SIGSYS      34) SIGRTMIN    35) SIGRTMIN+1  36) SIGRTMIN+2  37) SIGRTMIN+3
38) SIGRTMIN+4  39) SIGRTMIN+5  40) SIGRTMIN+6  41) SIGRTMIN+7  42) SIGRTMIN+8
43) SIGRTMIN+9  44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9  56) SIGRTMAX-8  57) SIGRTMAX-7
58) SIGRTMAX-6  59) SIGRTMAX-5  60) SIGRTMAX-4  61) SIGRTMAX-3  62) SIGRTMAX-2
63) SIGRTMAX-1  64) SIGRTMAX

时钟中断(了解)

时钟中断是计算机硬件体系结构中的一个重要特性,它为操作系统提供了一个周期性的触发点,使得操作系统能够在规定的时间间隔基础上进行一系列关键的系统管理操作。以下是对时钟中断的详细解释:

发生原理: 时钟中断通常由计算机系统内部的一个定时器硬件设备产生。这个定时器(有时也称为滴答定时器或心跳定时器)基于硬件计数器工作,每当计数器递增达到预设的阈值时,会产生一个电信号,向中央处理器(CPU)发出中断请求。操作系统通过配置定时器的计数速率,可以设定时钟中断的频率,这个频率通常以毫秒级别进行设置。

核心作用:

  1. 任务调度:时钟中断是操作系统进行进程调度的主要依据之一。每当发生时钟中断,操作系统会暂停当前正在执行的进程,并保存其现场(上下文),然后根据调度策略选择下一个高优先级或等待时间片耗尽的进程继续执行。这种机制实现了多任务的并发执行(尽管在单核CPU上实际上是轮流执行),使各进程能够共享CPU资源,提高了系统的并发性能和响应能力。

  2. 时间管理:时钟中断用于维护系统的全局时间,包括但不限于系统时钟、进程运行时间统计、定时器超时检测等。操作系统通过累计时钟中断次数来更新系统时间,确保了系统时间的准确性和实时性。

  3. 实时性支持:在实时操作系统(RTOS)中,时钟中断更加重要,因为它为系统提供了严格的时间基线,确保了关键任务能够按照预定的时间间隔得到及时执行,满足实时性要求。

  4. 硬件同步与I/O轮询:时钟中断也可能用于硬件同步操作,例如与网络设备的时间同步或周期性检查I/O设备的状态,确保CPU在设备准备就绪时迅速响应。

  5. 总结: 时钟中断是操作系统的心跳,它赋予了系统时间感知能力和任务切换机制。通过周期性地打断CPU的连续执行,操作系统得以执行后台管理和调度任务,确保了系统资源的合理分配和高效使用。

4、信号定义、kill -l查看信号列表

信号是一种操作系统机制,用于在进程间实现事件的异步通信和通知,其本质上属于软件层面的中断处理方式。当一个进程接收到信号时,它会暂停当前任务的执行,并转而去响应预先定义好的信号处理程序,从而实现进程间的非同步交互。简而言之,信号作为一种软中断手段,能够在进程之间高效、灵活地传播事件信息和触发相应动作。

信号列表:

kill -l命令在Unix/Linux系统中用于列出系统内建的所有信号及其对应的数字编号。信号是操作系统用于进程间通信或控制进程行为的一种机制,例如通知进程结束运行、报告错误状态或者要求进程执行某种特定动作。

每个信号都有一个独一无二的整数编号,并且在C/C++编程中,通过包含<signal.h>头文件可以访问到这些信号对应的宏定义名称。例如,宏定义SIGINT通常代表的是中断信号(Ctrl+C产生的信号),其对应的信号编号是2。

[hbr@VM-16-9-centos signal]$ kill -l1) SIGHUP       2) SIGINT       3) SIGQUIT      4) SIGILL       5) SIGTRAP6) SIGABRT      7) SIGBUS       8) SIGFPE       9) SIGKILL     10) SIGUSR1
11) SIGSEGV     12) SIGUSR2     13) SIGPIPE     14) SIGALRM     15) SIGTERM
16) SIGSTKFLT   17) SIGCHLD     18) SIGCONT     19) SIGSTOP     20) SIGTSTP
21) SIGTTIN     22) SIGTTOU     23) SIGURG      24) SIGXCPU     25) SIGXFSZ
26) SIGVTALRM   27) SIGPROF     28) SIGWINCH    29) SIGIO       30) SIGPWR
31) SIGSYS      34) SIGRTMIN    35) SIGRTMIN+1  36) SIGRTMIN+2  37) SIGRTMIN+3
38) SIGRTMIN+4  39) SIGRTMIN+5  40) SIGRTMIN+6  41) SIGRTMIN+7  42) SIGRTMIN+8
43) SIGRTMIN+9  44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9  56) SIGRTMAX-8  57) SIGRTMAX-7
58) SIGRTMAX-6  59) SIGRTMAX-5  60) SIGRTMAX-4  61) SIGRTMAX-3  62) SIGRTMAX-2
63) SIGRTMAX-1  64) SIGRTMAX

对于标准信号,即编号小于等于33的那些信号,它们是内建于大多数Unix-like系统的基本信号集(普通信号)。例如:

  • SIGHUP(1):终端挂断或会话首进程退出时发出。
  • SIGINT(2):用户按下中断键(通常是Ctrl+C)时产生。
  • SIGQUIT(3):用户按下退出键(通常是Ctrl+\)时产生。
  • SIGKILL(9):无条件终止进程信号,不可被捕获或忽略。
  • SIGTERM(15):请求进程正常终止的信号,可被捕获并自定义处理。

而编号34及以上的信号称为实时信号,它们是为了满足特定需求而设计的额外信号,主要用于实现更高优先级或更精确的进程间同步与通信,且通常具有更高的优先级。

  • 在Unix/Linux系统中,通过查阅man 7 signal手册页可以获得更加详细的信号列表,包括每种信号何时由操作系统产生(触发条件)、它们默认的行为(比如是否会导致进程终止、暂停或继续执行),以及如何更改这些信号的默认处理方式等内容。

5、信号处理的常见方式

在计算机系统中,对于接收到的信号,常见的处理方式包括但不限于以下三种策略:

  1. 忽略信号:这种处理方式允许进程选择不响应特定的信号,即当接收到该信号时不进行任何操作,任由信号自然消逝。例如,进程可以选择忽略某些不影响其正常运行的非关键性信号。

  2. 执行默认处理动作:每个信号都有一个系统预设的默认处理动作。当接收到信号时,进程可以选择按照系统的默认方式进行响应。比如,SIGINT(中断)信号的默认处理通常是终止进程,而SIGSEGV(段错误)信号的默认处理通常是结束进程并生成core dump文件。

  3. 捕捉信号(Signal Catching):这是一种更为精细的信号处理方式,允许进程为特定信号注册一个自定义的信号处理函数。当指定的信号发生时,操作系统会暂停当前进程,并切换到用户态执行预先设定好的处理函数。这样,进程可以根据自身需求实现更灵活、个性化的信号响应逻辑。通过这种方式,进程能够捕捉并针对性地处理各种可能出现的异常情况或进行特定的程序控制流转。

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

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

相关文章

基于《2023腾讯云容器和函数计算技术实践精选集》—探索腾讯云TKE的Docker容器、Serverless和微服务优势

重剑无锋&#xff0c;大巧不工。 ——金庸 腾讯云TKE&#xff0c;全称Tencent Kubernetes Engine&#xff0c;是一种完全托管式的容器服务。它可以帮助用户快速、高效地部署和管理Kubernetes集群&#xff0c;并提供一系列与之相关的云服务&#xff0c;如负载均衡、云硬盘、对象…

汇编语言第四版-第3章 寄存器(内访问)

al为ax的低字节&#xff0c;ax寄存器为累加器。

Vue element-plus 导航栏 [el-menu]

导航栏 [el-menu] Menu 菜单 | Element Plus el-menu有很多属性和子标签&#xff0c;为网站提供导航功能的菜单。 常用标签&#xff1a; 它里面有两个子标签。el-menu-item&#xff0c;它其实就是el-menu每一个里面的item&#xff0c;item就是真实匹配到路由的每个栏目&#…

Unity3d使用Jenkins自动化打包(Windows)(一)

文章目录 前言一、安装JDK二、安装Jenkins三、Jenkins插件安装和使用基础操作 实战一基础操作 实战二 四、离线安装总结 前言 本篇旨在介绍基础的安装和操作流程&#xff0c;只需完成一次即可。后面的篇章将深入探讨如何利用Jenkins为Unity项目进行打包。 一、安装JDK 1、进入…

机器学习优化算法(深度学习)

目录 预备知识 梯度 Hessian 矩阵&#xff08;海森矩阵&#xff0c;或者黑塞矩阵&#xff09; 拉格朗日中值定理 柯西中值定理 泰勒公式 黑塞矩阵&#xff08;Hessian矩阵&#xff09; Jacobi 矩阵 优化方法 梯度下降法&#xff08;Gradient Descent&#xff09; 随机…

Python问题列表

文章目录 1、使用pip安装的模块都存放到哪里了&#xff1f;2、安装fitz包报错&#xff0c;如何解决&#xff1f;3、python代码运行时&#xff0c;控制台输出乱码如何解决。4、vscode中第三方库不自动补齐 1、使用pip安装的模块都存放到哪里了&#xff1f; 答&#xff1a; pip是…

【OpenGL】使用 python + Qt + OpenGL 的现代渲染

伴随资源 目录 一、说明二、 关于PyQt6.x2.1 QOpenGLWidget详细说明2.2 绘画技巧 三、PyOpenGL四、OpenGL 管线五、Python集成开发环境5.1 Emacs配置5.2 pycharm环境 六、你好&#xff0c;OpenGL&#xff01;七、QGL控件八、平截头体.svg九、定义几何9.1 立即模式与保留模式9…

如何在Portainer中创建Nginx服务并搭建静态站点实现公网访问本地网站

文章目录 前言1. 安装Portainer1.1 访问Portainer Web界面 2. 使用Portainer创建Nginx容器3. 将Web静态站点实现公网访问4. 配置Web站点公网访问地址4.1公网访问Web站点 5. 固定Web静态站点公网地址6. 固定公网地址访问Web静态站点 前言 Portainer是一个开源的Docker轻量级可视…

ES学习日记(一)-------单节点安装启动

基于ES7.4.1编写,其实一开始用的最新的8.1,但是问题太多了!!!!不稳定,降到7.4 下载好的安装包上传到服务器或虚拟机,创建ES目录,命令mkdir -p /路径xxxx 复制安装包到指定路径并解压: tar zxvf elasticsearch-8.1.0-linux-x86_64.tar.gz -C /usr/local/es/ 进入bin目录安装,命…

JAVA学习笔记21(访问修饰符)

1.访问修饰符 ​ *基本介绍 ​ java提供四种访问控制修饰符号&#xff0c;用于控制方法和属性(成员变量)的访问权限(范围) 1.公开级别&#xff1a;用public修饰&#xff0c;对外公开 2.受保护级别&#xff1a;用protected修饰&#xff0c;对子类和同一个包中的类公开 3.默…

Linux基本指令篇

在前边&#xff0c;我们已经了解过了Linux操作系统的发展和应用&#xff0c;从该篇起&#xff0c;就正式进入对Linux的学习。 今天我们就来在Xshell上远程登录我们的云服务器。首先我们要知道自己云服务器的公网ip&#xff0c;然后修改一下密码。 点击跳转 修改完密码之后我们…

java题目15:从键盘输入n个数,求这n个数中的最大数与最小数并输出(MaxAndMin15)

每日小语 你是否有资格摆脱身上的枷锁呢&#xff1f;有许多人一旦获得解放&#xff0c;他的最后一点价值也就会跟着丧失。 ——尼采 自己敲写 它不按我想的来。。。 //从键盘输入n个数&#xff0c;求这n个数中的最大数与最小数并输出 import java.util.Scanner; public clas…

2024年美团笔试题(1)

一.题目描述 小美拿到了一个排列&#xff0c;其中初始所有元素都是红色&#xff0c;但有些元素被染成了白色。 小美每次操作可以选择交换任意两个红色元素的位置。她希望操作尽可能少的次数使得数组变成非降序&#xff0c;你能帮帮她吗? 排列是指:一个长度为n的数组&#…

【跟着CHATGPT学习硬件外设 | 02】GPIO

文章目录 &#x1f680; 概念揭秘快速入门关键精华 &#x1f31f; 秒懂案例生活类比实战演练步骤1&#xff1a;硬件配置步骤2&#xff1a;软件配置步骤3&#xff1a;发送和接收数据步骤4&#xff1a;处理异常步骤5&#xff1a;优化操作手册硬件设计注意事项配置攻略准备阶段配置…

镭速如何解决UDP传输不通的问题

我们之前有谈到过企业如果遇到UDP传输不通的情况&#xff0c;常见的一些解决方式&#xff0c;同时也介绍了一站式企业文件传输方式-镭速相关优势&#xff0c;如果在实际应用中&#xff0c;若镭速UDP传输出现不通的情况&#xff0c;需要按照网络通信的一般性排查方法以及针对镭速…

Git--08--Git分支合并操作

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 Git分支合并操作案例流程客户端&#xff1a;GitExtensions操作步骤&#xff1a;A操作步骤&#xff1a;B操作步骤&#xff1a;C操作步骤&#xff1a;D操作步骤&#…

SOC内部集成网络MAC外设+ PHY网络芯片方案:MII/RMII 接口与 MDIO 接口

一. 简介 本文来了解一下常用的一种网络硬件方案&#xff1a;SOC内部集成网络MAC外设 PHY网络芯片方案。 其中涉及的 MII接口&#xff0c;RMII接口&#xff08;MII接口与RMII接口二选一&#xff09;&#xff0c;MDIO接口&#xff0c;RJ45。 二. MII/RMII 接口&#xff0c;M…

Platypus 一种集中式的央行数字货币方案

集中式的CBDC&#xff0c;混合使用账户模型和UTXO模型。 角色分类 中央银行&#xff1a;发行货币&#xff0c;交易验证&#xff0c;公开交易日志&#xff0c;防止双花。 不是完全受信任的&#xff0c;假定为会遵守监管要求&#xff0c;但可能会破坏交易隐私&#xff0c;即获…

关系型数据库mysql(8)sql高级语句②

目录 一.子查询——Subquery 语法 环境准备 In——查询已知的值的数据记录 子查询——Insert 子查询——Update 子查询——Delete Not In——表示否定&#xff0c;不在子查询的结果集里 Exists——判断查询结果集是否为空 子查询——别名 ​编辑 二.视图 理论&a…

TransmittableThreadLocal 问题杂记

0、前言 TransmittableThreadLocal&#xff0c;简称 TTL&#xff0c;是阿里巴巴开源的一个Java库&#xff0c;它能够实现ThreadLocal在多线程间的值传递&#xff0c;适用于使用线程池、异步调用等需要线程切换的场景&#xff0c;解决了ThreadLocal在使用父子线程、线程池时不能…