【Linux】信号保存{sigset_t/sigpending/sigprocmask/bash脚本/代码演示}

文章目录

  • 1.信号相关常见概念
  • 2.管理信号的数据结构
  • 3.初识sigset_t
  • 4.信号集操作函数
    • 4.1sigpending
    • 4.2sigprocmask
    • 4.2代码测试
      • 1.测试1
      • 2.测试2
      • 3.测试3
    • 4.3bash 脚本文件


在这里插入图片描述

1.信号相关常见概念

信号相关动作:产生 发送 接收 阻塞 递达(处理)
实际执行信号的处理动作称为信号递达(Delivery)
信号从产生到递达之间的状态 称为信号未决(Pending)
进程可以选择阻塞 (Block )某个信号
信号产生后未被递达前 或 被阻塞的信号 将保持在未决状态 直到进程解除对此信号的阻塞 才执行递达的动作

阻塞信号和忽略信号的区别

阻塞和忽略是不同的 只要信号被阻塞就不会递达 而忽略是在递达之后可选的一种处理动作
忽略: 对信号已经进行了处理,处理方式是不做处理
阻塞:压根就没有对信号进行处理。

2.管理信号的数据结构

在这里插入图片描述
在这里插入图片描述

  1. 在进程PCB中,信号的pending位图、block位图和handler函数指针数组是用于管理信号处理的数据结构。
  2. 每个信号都有两个标志位分别表示阻塞(block)和未决(pending) 以及一个函数指针数组表示处理动作
  3. 信号产生未被递达时 内核在进程控制块中设置该信号的未决标志 直到信号递达才清除该标志
  4. a. 上图SIGHUP信号未阻塞也未产生过 当它递达时执行默认处理动作
    b. SIGINT信号产生了 但正在被阻塞 暂时不能递达 虽然它的处理动作是IGN(忽略) 但在没有解除阻塞之前 这个信号是不能进行处理即去忽略的 【在解除阻塞前进程仍有机会改变处理动作】
    c. SIGQUIT信号未产生过 一旦产生SIGQUIT信号将被阻塞 它的处理动作是用户自定义函sighandler

如果在进程解除对某信号的阻塞之前 这种信号产生过多次 将如何处理?

POSIX.1允许系统递送该信号一次或多次。
Linux是这样实现的:常规信号在递达之前产生多次只计一次 而实时信号在递达之前产生多次可以依次放在一个队列里。本章不讨论实时信号。

解读相关数据结构

在这里插入图片描述

在Linux下,PCB(进程控制块)的pending位图与信号的处理紧密相关。pending位图主要表示已经收到但是还没有被递达的信号。换句话说,当一个进程接收到一个信号,但这个信号尚未被进程处理(例如,因为进程当前正在执行某个不允许被中断的操作,或者信号的处理函数尚未被执行),那么这个信号的状态就会被记录在pending位图中。

pending位图的作用在于跟踪哪些信号已经到达进程但尚未被处理。这允许操作系统在适当的时机递达这些信号,比如当进程处于可以安全处理信号的状态时。通过这种方式,pending位图确保了信号的可靠传递和处理,防止了信号的丢失或重复处理。

在更深入地理解pending位图时,还需要考虑其他与信号相关的PCB属性,如block位图(表示哪些信号不应该被递达,直到解除阻塞)和信号屏蔽字(handle函数指针数组,用于定义每个信号的处理方式)。这些属性与pending位图一起,共同构成了Linux中进程信号处理的复杂而精细的机制。

总的来说,pending位图是Linux进程控制块中用于跟踪和管理已接收但尚未处理信号的重要数据结构,它确保了信号的可靠性和高效性。
Pending信号集:每个进程都有一个pending位图,用于记录当前已经被该进程接收但尚未处理(递达)的信号(未决信号)。当一个信号被接收时,对应的位会被设置为1,表示该信号已产生处于未决状态,直到信号递达(处理)才清除该标志。进程可以通过检查pending位图来确定是否有已产生未处理的信号。在Linux中,可以使用sigpending函数来获取当前进程的pending位图。

Block信号屏蔽字:每个进程都有一个block位图,用于指定当前被阻塞的信号。当一个信号被阻塞时,对应的位会被设置为1,表示该信号被阻塞,暂时不会被递达。进程可以通过设置block位图来控制哪些信号被阻塞,以避免进程在关键时刻被中断。在Linux中,可以使用sigprocmask函数来设置和获取当前进程的block位图。

Handler函数指针数组:每个进程都有一个handler函数指针数组,用于管理信号处理函数。该数组的索引对应于信号的编号,数组的元素是函数指针,指向相应信号的处理函数。当进程接收到一个信号时,会根据信号的编号在handler函数指针数组中查找对应的处理函数,并调用该函数来处理信号。在Linux中,可以使用signal和sigaction函数来设置和获取信号处理函数。

之前我们的文章中signal函数自定义处理信号的原理:将信号处理函数的指针填入到handler数组对应信号编号的位置。
pending位图、block位图和handler函数指针数组是针对每个进程而言的,每个进程都有自己独立的位图和数组。这样可以实现不同进程对信号的独立管理和处理。

3.初识sigset_t

在这里插入图片描述

  1. 从上图来看,每个信号只有一个bit的未决标志,非0即1,不记录该信号产生了多少次,阻塞标志也是这样表示的。
  2. 未决和阻塞标志可以用相同的数据类型sigset_t来表示 sigset_t称为信号集 这个类型可以表示每个信号的“有效”或“无效”状态,在阻塞信号集中“有效”和“无效”的含义是该信号是否被阻塞,而在未决信号集中“有效”和“无效”的含义是该信号是否处于未决状态。
  3. 阻塞信号集也叫做当前进程的信号屏蔽字(Signal Mask),这里的“屏蔽”应该理解为阻塞而不是忽略。

什么是sigset_t?

sigset_t 是 Linux 系统中用于表示信号集的数据类型。信号集是一组信号的集合,这些信号可以是未决信号(即已经发送但尚未处理的信号)或阻塞信号(即当前被阻塞不处理的信号)。sigset_t 可以看作是一个由二进制位组成的大整数,每一位对应一个信号,某一位为 1 表示信号集中包含该信号,为 0 则表示不包含。

在编程中,可以使用多种函数来操作 sigset_t 类型的信号集。例如,sigemptyset() 函数用于创建一个空的信号集,sigaddset() 函数用于向信号集中添加信号,sigdelset() 函数用于从信号集中删除信号。

在多线程编程中,pthread_sigmask() 函数特别有用,它允许你在主线程中控制信号掩码。这个函数接受三个参数:一个操作方式(SIG_BLOCK、SIG_UNBLOCK 或 SIG_SETMASK),一个指向信号集的指针(表示要设置或修改的信号集),以及一个可选的指向旧信号集的指针(用于保存之前的信号集状态)。

需要注意的是,直接修改 sigset_t 类型的内部数据可能并不安全或有效,通常建议使用专门的函数来操作信号集。同时,处理信号和信号集时应当小心谨慎,以避免潜在的竞态条件或错误。

总的来说,sigset_t 是 Linux 系统中用于处理信号的重要数据类型,它提供了一种方便的方式来表示和操作信号集。通过相关的函数,你可以轻松地创建、修改和查询信号集,以满足不同的编程需求。

计算机常识

  1. 语言会提供.h,.hpp 和自定义类型
  2. OS也会提供.h,和 OS自定义的类型(为了让用户能够用接口,接口的参数又不能是语言里的类型,或者语言里没有这种类型)
  3. 语言的一些库函数如读写函数封装了系统接口,那么读写函数的头文件中有可能就包含了系统的头文件

理解sigset_t

sigset_t:user是可以直接使用该类型 与 用内置类型 && 自定义类型 没有任何差别

4.信号集操作函数

sigset_t类型对于每种信号用一个bit表示“有效”或“无效”状态,至于这个类型内部如何存储这些bit则依赖于系统实现,从使用者的角度是不必关心的,使用者只能调用以下函数来操作sigset_ t变量,而不应该对它的内部数据做任何解释,比如用printf直接打印sigset_t变量是没有意义的

sigset_t:不允许用户自己进行位操作,OS提供了对应的操作位图的方法

#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);
  1. 函数sigemptyset初始化set所指向的信号集,使其中所有信号的对应bit清零,表示该信号集不包含 任何有效信号。
  2. 函数sigfillset初始化set所指向的信号集,使其中所有信号的对应bit置1,表示该信号集的有效信号包括系统支持的所有信号。
  3. 在使用sigset_ t类型的变量之前,要调用sigemptyset或sigfillset做初始化,使信号集处于确定的状态。
  4. 初始化sigset_t变量之后就可以在调用sigaddset和sigdelset在该信号集中添加或删除某种有效信号。
  5. sigismember是一个布尔函数,用于判断一个信号集的有效信号中是否包含某种信号,若包含则返回1,不包含则返回0,出错返回-1。
  6. 这四个函数都是成功返回0,出错返回-1。

sigset_t:一定需要对应的系统接口来完成对应的功能,其中系统接口需要的参数,可能就包含了sigset_t定义的变量或者对象 接下来的4.1/4.2即为系统接口

4.1sigpending

OS通过这个接口将set给用户
在这里插入图片描述
sigpending 是一个在 Unix 和 Linux 系统中用于获取当前进程挂起信号集的函数。挂起信号集是指那些已经发送到进程,但尚未被处理的信号。

函数的原型如下:

c
int sigpending(sigset_t *set);
参数说明:

set:指向一个 sigset_t 类型的变量,函数会将当前进程的挂起信号集存储在这个变量中。
返回值:

如果成功,则返回 0。
如果失败,则返回 -1,并设置 errno 以指示错误。
sigpending 函数允许进程查询哪些信号当前处于挂起状态,即哪些信号已经发送给进程但尚未被处理。这对于进程来说是非常有用的信息,因为它可以根据这些信息来决定如何响应这些挂起信号,或者进行其他相关操作。

注意,sigpending 函数返回的是挂起信号集,而不是当前进程的信号屏蔽字。挂起信号集是那些已经发送但尚未处理的信号,而信号屏蔽字则决定了哪些信号当前被进程阻塞。因此,即使某个信号在挂起信号集中,如果它也在信号屏蔽字中,那么进程也不会立即响应它。

使用 sigpending 时,通常需要与 sigprocmask 等函数结合使用,以便进程能够更全面地控制和处理信号。

4.2sigprocmask

在这里插入图片描述
sigprocmask 是一个在 Unix 和 Linux 系统中用于检查和/或更改当前进程的信号屏蔽字的函数。信号屏蔽字是一个位掩码,用于控制哪些信号当前应该被进程阻塞(即忽略)。

函数的原型如下:

c
int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
参数说明:

how:指定如何修改当前的信号屏蔽字。它可以是以下三个值之一:

SIG_BLOCK:将 set 所指向的信号集中的信号添加到当前的信号屏蔽字中。mask |= set
SIG_UNBLOCK:从当前的信号屏蔽字中移除 set 所指向的信号集中的信号。mask = mask &~set
SIG_SETMASK:将当前的信号屏蔽字设置为 set 所指向的信号集。mask = set
set:指向一个 sigset_t 类型的变量,该变量包含了一组信号,这些信号将根据 how 参数的值被添加到、从或从当前信号屏蔽字中移除。

oldset:如果此参数不是 NULL,则函数会将调用前的信号屏蔽字存储在 oldset 所指向的 sigset_t 变量中。

返回值:

如果成功,则返回 0。
如果失败,则返回 -1,并设置 errno 以指示错误。
sigprocmask 函数允许进程精细地控制哪些信号应被阻塞。这对于实现多线程程序中的同步机制,或者在执行某些不能被信号中断的临界区代码时特别有用。通过阻塞某些信号,进程可以确保在关键代码段执行期间不会被这些信号中断。

注意,sigprocmask 修改的是调用进程的信号屏蔽字,因此它只对调用它的进程有效。此外,阻塞的信号仍然可以被进程接收,只是它们不会中断进程的执行,直到信号屏蔽字被修改以允许这些信号为止。

4.2代码测试

1.测试1

如果我们对所有的信号都进行了自定义捕捉 我们是不是就写了一个不会被异常或者用户杀掉的进程? 并不是,OS的设计者也考虑了
在这里插入图片描述

在这里插入图片描述在这里插入图片描述
9号信号不可被捕获 ⇒ 管理员信号

2.测试2

如果我们将2号信号block,并且不断的获取并打印当前进程的pending信号集,如果我们突然发送一个2号信号,我们就应该肉眼看到pending信号集中,有一个比特位0->1

#include <iostream>
#include <signal.h>
#include <unistd.h>
#include <cassert>

static void showPending(sigset_t &pending)
{
    for (int sig = 31; sig >=1; sig--)
    {
        if (sigismember(&pending, sig))
            std::cout << "1";
        else
            std::cout << "0";
    }
    std::cout << std::endl;
}

int main()
{
    // 1. 定义信号集对象
    sigset_t set, oldset, pending;
    // 2. 初始化
    sigemptyset(&set);
    sigemptyset(&oldset);
    sigemptyset(&pending);
    // 3. 添加要进行屏蔽的信号
    sigaddset(&set, 2 /*SIGINT*/);
    // 4. 将set添加到当前的信号屏蔽字中(内核的进程内部)
    //[默认情况进程不会对任何信号进行block]
    int n = sigprocmask(SIG_BLOCK, &set, &oldset);
    assert(n == 0);
    (void)n;

    std::cout << "block 2 signal success...., pid: " << getpid() << std::endl;
   
    // 5. 重复打印当前进程的pending信号集
    while (true)
    {
        // 5.1 获取当前进程的pending信号集
        sigpending(&pending);
        // 5.2 显示pending信号集中信号状态
        showPending(pending);
        sleep(1);
    }

    return 0;
}

在这里插入图片描述
在这里插入图片描述

  • 如果解除2号信号的阻塞 会发生什么?
#include <iostream>
#include <signal.h>
#include <unistd.h>
#include <cassert>

static void handler(int signum)
{
    std::cout << "捕获信号:" << signum << std::endl;
    // exit(1); 不终止进程
}

static void showPending(sigset_t &pending)
{
    for (int sig = 1; sig <= 31; sig++)
    {
        if (sigismember(&pending, sig))
            std::cout << "1";
        else
            std::cout << "0";
    }
    std::cout << std::endl;
}

int main()
{
    // 0. 测试 捕捉2号信号 不让其执行默认终止动作
    signal(2, handler);
    // 1. 定义信号集对象
    sigset_t set, oldset;
    sigset_t pending;
    // 2. 初始化
    sigemptyset(&set);
    sigemptyset(&oldset);
    sigemptyset(&pending);
    // 3. 添加要进行屏蔽的信号
    sigaddset(&set, 2 /*SIGINT*/);
    // 4. 设置set到内核中对应的进程内部[默认情况进程不会对任何信号进行block]
    int n = sigprocmask(SIG_BLOCK, &set, &oldset);
    assert(n == 0);
    (void)n;

    std::cout << "block 2 号信号成功...., pid: " << getpid() << std::endl;
    // 5. 重复打印当前进程的pending信号集
    int count = 0;
    while (true)
    {
        // 5.1 获取当前进程的pending信号集
        sigpending(&pending);
        // 5.2 显示pending信号集中的没有被递达的信号
        showPending(pending);
        sleep(1);
        count++;
        if (count == 20)
        {
            // 默认情况下 解除2号信号的阻塞 确实会进行递达
            // 2号信号的默认处理动作是终止进程 需要对2号信号进行捕捉
            std::cout << "Unblock signal 2" << std::endl;
            int n = sigprocmask(SIG_SETMASK, &oldset, nullptr);
            assert(n == 0);
            (void)n;
        }
    }

    return 0;
}

在这里插入图片描述

在这里插入图片描述

上面0和1的顺序是可以通过输出格式控制的逆序遍历 ⇒ 正向输出

我们可以获取sigpending 貌似没有一一个接口用来设置pending位图(所有的信号发送方式,都是修改pending位图的过程)

3.测试3

如果我们对所有的信号都进行block 我们是不是就写了一个不会被异常或者用户杀掉的进程

监测指令

i=1; id=$(pidof mysignal);\
> while [ $i -le 31 ]; do echo "i: $i, id: $id";\
> let i++; sleep 1; done

i=1; id=$(pidof mysignal);\
> while [ $i -le 31 ]; do kill -$i $id; \
> echo "sending signal $i";\
> let i++; sleep 1; done

在这里插入图片描述在这里插入图片描述
9号信号也不可以被屏蔽/阻塞

SIGKILL(9)信号 和 SIGSTOP(19)信号 不能被捕捉,也不能被阻塞。20号信号默认动作是忽略(猜测)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

#include <iostream>
#include <signal.h>
#include <unistd.h>
#include <cassert>

static void showPending(sigset_t &pending)
{
     for (int sig = 31; sig >= 1; sig--)
    {
        if (sigismember(&pending, sig))
            std::cout << "1";
        else
            std::cout << "0";
    }
    std::cout << std::endl;
}

static void blockSig(int sig)
{
    sigset_t set;
    sigemptyset(&set);
    sigaddset(&set, sig);
    int n = sigprocmask(SIG_BLOCK, &set, nullptr);
    assert(n == 0);
    (void)n;
}

int main()
{
    for(int sig = 1; sig <= 31; sig++)
    {
        blockSig(sig);
    }
    
    sigset_t pending;
    while(true)
    {
        sigpending(&pending);
        showPending(pending);
        sleep(1);
    }
    return 0;
}

在这里插入图片描述在这里插入图片描述

4.3bash 脚本文件

#!/bin/bash

i=1
id=$(pidof mysignal)
while [ $i -le 31 ]
do
    if [ $i -eq 9 ];then
        let i++
        continue
    fi
    if [ $i -eq 19 ];then
        let i++
        continue
    fi
    kill -$i $id
    echo "kill -$i $id"
    let i++
    sleep 1
done

#!/bin/bash
这一行称为 shebang 或 hashbang。它告诉操作系统该脚本应该使用哪个解释器来执行。在这个例子中,它指定了使用 /bin/bash,也就是 Bourne Again SHell 的路径,这是许多 Linux 和 Unix 系统中的默认 shell。当你尝试运行这个脚本时(例如,通过输入 ./scriptname.sh),操作系统会查看脚本的第一行,并使用 /bin/bash 来解释和执行脚本的内容。
2. if … then … fi

这是 Bash 中的条件语句结构。它用于根据某个条件是否满足来执行不同的代码块。

  • if [ 条件 ]:检查后面的条件是否满足。如果满足,则执行 then 后面的代码块。
  • then:表示如果前面的条件满足,则执行接下来的代码块。
  • fi:表示 if 语句的结束。
    在你的脚本中,有两个 if 语句,分别检查 $i 是否等于 9 或 19。如果等于这两个值,脚本会跳过发送信号的部分,并直接继续到下一个循环迭代。
  1. then

如上所述,then 关键字用于 if 语句中,表示如果前面的条件满足,则执行 then 后面的代码块。

为了更清楚地理解,让我们看一个简化的例子:

bash
#!/bin/bash  
  
number=5  
  
if [ $number -eq 5 ]; then  
    echo "The number is 5."  
fi

在这个例子中,脚本会检查变量 number 是否等于 5。如果是,它会输出 “The number is 5.”。fi 表示 if 语句的结束。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Spring Boot中application配置文件的生效顺序

Spring Boot的一个重要特性就是它的自动配置&#xff0c;这一特性在很大程度上依赖于名称为application的配置文件。本文将详细介绍在Spring Boot中&#xff0c;这些配置文件的加载顺序以及每份文件的应用范围。 文章目录 配置文件的种类配置文件的加载顺序配置文件的环境切换 …

一起玩儿3D打印机——03 Marlin固件的获取和安装环境的配置

摘要&#xff1a;本文介绍Marlin固件的获取和安装环境的配置 Marlin是一款开源软件&#xff0c;其主页为&#xff1a;https://marlinfw.org/&#xff0c;首页正中就是下载连接&#xff0c;如下图所示&#xff1a; 单击下面的“Download Marlin 2.1.2.2”按钮就会进入下载页面&a…

图形设计软件 CorelDRAW Graphics Suite 2024 v25.0.0.230 中文破解版

CorelDRAW Graphics Suite (简称CDR) 是加拿大Corel公司开发的一款功能强大的专业平面设计软件、矢量设计软件、矢量绘图软件。软件广泛应用于商标设计、标志制作、封面设计、CIS设计、产品包装造型设计、模型绘制、插图描画、时装/服饰设计、印刷制版、排版及分色输出等诸多领…

linux查看top与修改root密码

top perf top -g -p 进程名 使用top命令&#xff0c;同时输入大写的P&#xff0c;会按照cpu使用率从大到小排列 linux修改用户登录密码 输入Ctrlx进入下面的界面 分别输入mount -o remount, rw / 注意rw后面又两个空格 输入passwd root 修改root密码 输入新密码2次 ex…

三、传输层拥塞控制、差错控制

3.1 概述和传输层服务 传输服务和协议&#xff1a; 为运行在不同主机上的应用进程提供逻辑通信&#xff1b; 传输协议运行在端系统-发送方:将应用层的报文分成报文段&#xff0c;然后传递给网络层&#xff1b;接收方&#xff1a;将报文段重组成报文&#xff0c;然后传递给应用…

解决分布式事务,Seata真香!

年IT寒冬&#xff0c;大厂都裁员或者准备裁员&#xff0c;作为开猿节流主要目标之一&#xff0c;我们更应该时刻保持竞争力。为了抱团取暖&#xff0c;林老师开通了《知识星球》&#xff0c;并邀请我阿里、快手、腾讯等的朋友加入&#xff0c;分享八股文、项目经验、管理经验等…

Anaconda安装proplot库

看了一下Anaconda中的环境&#xff0c;现在我有4个&#xff0c;其中gee是一个虚拟环境 因此一般在prompt中装库时要先进入其中一个虚拟环境 conda activate geepip install proplot --no-deps下完了之后&#xff0c;发现版本不对应 conda install matplotlib3.4.3

传输层 | UDP | TCP

目录 一、再谈端口号 (一) 端口号范围划分 (二) 认识知名端口号 (三) netstat (四) pidof 二、UDP协议 (一) UDP协议端格式 (二) UDP的特点 (三) 面向数据报 (四) UDP的缓冲区 (五) UDP使用注意事项 (六) 基于UDP的应用层协议 三、TCP协议 (一) TCP协议的段格式 …

数据结构——lesson8二叉树的实现

&#x1f49e;&#x1f49e; 前言 hello hello~ &#xff0c;这里是大耳朵土土垚~&#x1f496;&#x1f496; &#xff0c;欢迎大家点赞&#x1f973;&#x1f973;关注&#x1f4a5;&#x1f4a5;收藏&#x1f339;&#x1f339;&#x1f339; &#x1f4a5;个人主页&#x…

鸿蒙Harmony应用开发—ArkTS声明式开发(基础手势:Web)中篇

onBeforeUnload onBeforeUnload(callback: (event?: { url: string; message: string; result: JsResult }) > boolean) 刷新或关闭场景下&#xff0c;在即将离开当前页面时触发此回调。刷新或关闭当前页面应先通过点击等方式获取焦点&#xff0c;才会触发此回调。 参数…

Parade Series - Web Streamer Low Latency

Parade Series - FFMPEG (Stable X64) 延时测试秒表计时器 ini/config.ini [system] homeserver storestore\nvr.db versionV20240312001 verbosefalse [monitor] listrtsp00,rtsp01,rtsp02 timeout30000 [rtsp00] typelocal deviceSurface Camera Front schemartsp ip127…

uniapp,导航栏(切换项)有多项,溢出采取左滑右滑的形式展示

一、实现效果 当有多项的导航&#xff0c;或者说切换项&#xff0c;超出页面的宽度&#xff0c;我们采取可滑动的方式比较好一些&#xff01;并且在页面右边加个遮罩&#xff0c;模拟最右边有渐变效果&#xff01; 二、实现代码 html代码&#xff1a; <!-- 头部导航栏 --…

Linux:系统初始化,内核优化,性能优化(3)

优化系统的文件句柄数&#xff08;全局&#xff09; 也就是系统的最大文件数量 查看最大数量 cat /proc/sys/fs/file-max 当我们的服务器有非常大的一个数据并发的时候十几二十万的文件需要去配置&#xff0c;可能这个是远远不够的&#xff0c;我们就要去修改 vim /etc/sy…

【系统架构师】-第4章-信息安全技术

1、基础知识 五要素&#xff1a; (1)机密性&#xff1a;确保信息不暴露给未授权的实体或进程。 (2)完整性&#xff1a;只有得到允许的人才能修改数据&#xff0c;并且能够判别出数据是否已被篡改。 (3)可用性&#xff1a;得到授权的实体在需要时可访问数据&#xff0c;即攻击…

DFL《384底丹 430万》 wf/df-udt/448/96/96/32预训练模型

384底丹430万迭代&#xff1a;点击下载 训练素材19万张来自于以下数据集&#xff1a; 【更新】DST全角度训练图集V3.1 WF512【2.6W张 6GB 】【人脸混合_WF】FFHQ女性人脸数据&#xff0c;预训练炼丹专用【金鱼基础模型库】用于补全SRC极限角度香港中文大学CelebA预训练集-WF5…

【web前端】<meta>标签

meta元素可以提供有关页面的元信息&#xff08;meta-information&#xff09; meta标签位于文档的头部&#xff0c;是空元素 meta元素的属性 属性值描述http-equiv expires refresh X-UA-compatible 定义HTTP协议的头部元信息名称。其中&#xff0c;expires设置网页在缓存区的…

docker引擎

目录 一、Docker引擎发展历程 二、docker引擎架构 三、docker引擎分类 四、docker引擎安装 4.1安装条件 4.2 使用rpm存储库安装 4.2.1设置存储库 4.2.2安装docker引擎 4.2.3启动docker,并设置docker开机自启动 五、卸载docker引擎 5.1.卸载 Docker 引擎、CLI、conta…

如何使用人工智能打造超用户预期的个性化购物体验

回看我的营销职业生涯&#xff0c;我见证了数字时代如何重塑客户期望。从一刀切的方法过渡到创造高度个性化的购物体验已成为企业的关键。在这个客户期望不断变化的新时代&#xff0c;创造个性化的购物体验不再是奢侈品&#xff0c;而是企业的必需品。人工智能 &#xff08;AI&…

Acwing-基础算法课笔记之动态规划(计数类DP)

Acwing-基础算法课笔记之动态规划&#xff08;计数类DP&#xff09; 一、整数划分1、定义2、完全背包的做法代码示例&#xff08;1&#xff09;过程模拟&#xff08;2&#xff09;代码示例 3、计数类DP的做法&#xff08;1&#xff09;过程模拟&#xff08;2&#xff09;闫氏DP…

页面侧边栏顶部固定和底部固定方法

顶部固定用于侧边栏低于屏幕高度----左侧边栏 底部固定用于侧边栏高于屏幕高度----右侧边栏 vue页面方法 页面布局 页面样式&#xff0c;因为内容比较多&#xff0c; 只展示主要代码 * {margin: 0;padding: 0;text-align: center; } .head {width: 100%;height: 88px;back…