Linux 理解进程信号

news2024/11/26 8:38:52

目录

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

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 -l
 1) SIGHUP       2) SIGINT       3) SIGQUIT      4) SIGILL       5) SIGTRAP
 6) 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 -l
 1) SIGHUP       2) SIGINT       3) SIGQUIT      4) SIGILL       5) SIGTRAP
 6) 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.coloradmin.cn/o/1558882.html

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

相关文章

【面试题】RocketMQ如何保证消息不丢失?

前言&#xff1a;在面试的时候如果你会用消息中间件&#xff0c;那么面试一般都会问到MQ是如何保证消息不丢失的这个问题&#xff0c;所以这个问题对于面试和日常工作都非常之重要&#xff0c;本文主要讲述RocketMQ是如何保证消息不丢失的&#xff0c;但是我们可以举一反三&…

C语言操作符详细讲解

前言 本次博客一定会让刚刚学习C语言小白有所收获 本次操作符讲解不仅分类还会有代码示例 好好看 好好学 花上几分钟就可以避免许多坑 1 操作符的基本使用 1.1操作符的分类 按功能分 算术操作符&#xff1a; 、- 、* 、/ 、% 移位操作符: >> << 位操作符…

内存池的实现与场景分析

内存管理库 jemalloc 内存管理&#xff0c;C 语言。tcmalloc 内存管理&#xff0c;C。在头文件中引入即可。 确定 block 的大小、不确定 block 的释放时间&#xff0c;如何设计内存池 ? #include <stdio.h> #include <stdlib.h>// gcc mem_pool_v1.c -o mem_poo…

Linux: 进程优先级

Linux: 进程优先级 一、进程优先级概念二、如何查看进程优先级三、如何修改进程的优先级&#xff08;PRL vs NI&#xff09;四、为何优先级PRL必须限定范围五、进程其他特性 一、进程优先级概念 优先级的本质就是排队&#xff0c;而排队则是资源不足所引起的。在计算机中&#…

Sublime 彻底解决中文乱码

1. 按ctrl&#xff0c;打开Console&#xff0c;输入如下代码&#xff1a; import urllib.request,os; pf Package Control.sublime-package; ipp sublime.installed_packages_path(); urllib.request.install_opener( urllib.request.build_opener( urllib.request.ProxyHand…

LLM:函数调用(Function Calling)

1 函数调用 虽然大模型能解决很多问题&#xff0c;但大模型并不能知晓一切。比如&#xff0c;大模型不知道最新消息(GPT-3.5 的知识截至 2021年9月&#xff0c;GPT-4 是 2023 年12月)。另外&#xff0c;大模型没有“真逻辑”。它表现出的逻辑、推理&#xff0c;是训练文本的统计…

spring注解@EventListener实现监听原理

文章目录 EventListener使用方式EventListener实现原理1.引入时机2 初始化时机3 作用时机->将加了EventListener注解的方法识别出来&#xff0c;并封装为监听器&#xff0c;加载spring容器中 总结 EventListener使用方式 package com.cyl.listener;import org.springframew…

区间预测 | Matlab实现带有置信区间的GRNN广义回归神经网络时间序列未来趋势预测

文章目录 效果一览文章概述源码设计参考资料效果一览 文章概述 Matlab实现带有置信区间的GRNN广义回归神经网络时间序列未来趋势预测 带有置信区间的GRNN(广义回归神经网络)时间序列未来趋势预测结合了广义回归神经网络(GRNN)的预测能力和置信区间的统计度量,以提供对未来…

Linux系统下NAT网卡出现问题,无法上网的解决办法

NTA连接无法上网&#xff0c;如果你试过网上所有教程&#xff0c;检测了Windows环境和Ubuntu环境没问题&#xff0c;且无法启动系统服务、ping网络失败、重置虚拟机网络配置器也无效等种种以下所列原因无法解决&#xff0c;可能在于没有获取IP地址&#xff0c;才不能上网 netw…

Taskflow:运行时交互(Interact with the Runtime)

Taskflow允许您通过将运行时对象作为任务的参数与调度运行时进行交互。这主要用于设计从Taskflow的现有设施扩展的专用并行算法。 创建Runtime对象 Taskflow允许静态任务和条件任务接受引用的tf::Runtime对象&#xff0c;该对象提供一组方法与调度运行时交互。以下示例创建一…

CleanMyMac X中文---让Mac焕发新生,Mac优化与清理的终极利器

CleanMyMac X是一款专为Mac用户设计的综合性系统优化工具。通过智能扫描&#xff0c;它能够快速识别并清理Mac磁盘上的垃圾文件、重复文件、无用语言安装包、iTunes缓存、邮件附件等&#xff0c;有效释放磁盘空间&#xff0c;提升Mac电脑的运行速度。此外&#xff0c;CleanMyMa…

灵途科技助力家电智能创新

从智能家电到个护健康&#xff0c;科技无时无刻不在刷新我们对智慧生活的认知&#xff0c;我们也从未像今天这样近距离贴近智慧生活的朴素本质——传感技术。灵途科技专注光电感知技术&#xff0c;持续为智能家电客户提供成熟的全方位感知解决方案。步入发展第八年&#xff0c;…

本地搭建多人协作ONLYOFFICE文档服务器并结合Cpolar内网穿透实现公网访问远程办公

文章目录 1. 安装Docker2. 本地安装部署ONLYOFFICE3. 安装cpolar内网穿透4. 固定OnlyOffice公网地址 本篇文章讲解如何使用Docker在本地服务器上安装ONLYOFFICE&#xff0c;并结合cpolar内网穿透实现公网访问。 Community Edition允许您在本地服务器上安装ONLYOFFICE文档&…

【OpenGL】(1) 环境搭建:运行简单的 OpenGL 教学示例程序

&#x1f4ad; 写在前面&#xff1a;我们尽可能地让大家以 最简单粗暴且无脑的方式&#xff0c;带大家配置好 OpenGL 环境&#xff0c;并跑出我们第一个示例程序。再次声明&#xff0c;本专栏所有教学都是基于 Windows上使用 VS2022 (X64) 的。本专栏主要内容是关于 3D 计算机图…

【讲解下Gitea】

&#x1f308;个人主页:程序员不想敲代码啊 &#x1f3c6;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f44d;点赞⭐评论⭐收藏 &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff0c;让我们共…

anaconda navigator updater 版本更新失败

打开后&#xff0c;更新界面持续很久 使用命令行查看版本 执行conda update anaconda-navigator 第一次执行中间失败&#xff0c;重新执行&#xff0c;更新成功

基于深度学习YOLOv8+PyQt5的水底海底垃圾生物探测器检测识别系统(源码+数据集+配置说明)

wx供重浩&#xff1a;创享日记 对话框发送&#xff1a;323海底 获取完整源码7000张数据集配置说明文件说明远程操作配置环境跑通程序 效果展示 基于深度学习YOLOv8PyQt5的水底海底垃圾生物探测器检测识别系统设计&#xff08;源码数据集配置文件&#xff09; 各文件说明 程序运…

网页布局案例 浮动

这里主要讲浮动 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>Title</title><style>*{padding: 0;margin: 0;}.header{height: 40px;background-color: #333;}.nav{width: 1226px;heig…

【Java 多线程】从源码出发,剖析Threadlocal的数据结构

文章目录 exampleset(T value)createMap(t, value);set(ThreadLocal<?> key, Object value)ThreadLocalMap和Thread的关系 全貌 ThreadLocal是个很重要的多线程类&#xff0c;里面数据结构的设计很有意思&#xff0c;很巧妙。但是我们平时使用它的时候常常容易对它的使用…

学习【Redis高级篇】这一篇就够了

目录 1. 分布式缓存1-1. Redis持久化RDB持久化AOF持久化RDB与AOF对比总结 1-2. Redis主从集群全量同步增量同步主从优化总结 1-3. Redis哨兵哨兵作用集群监控原理集群故障恢复原理RedisTemplate访问哨兵总结 1-4. Redis分片集群散列插槽集群伸缩故障转移 2. 多级缓存2-1. 浏览器…