【Linux】进程信号

2023-10-29

1.理解信号

1.信号:能够识别并做出行为的一种指令

2.信号来临的时候不一定能够立即对信号做出处理,但是并不影响信号的产生。

3.信号来临------>-------时间窗口------>------>被处理,结果是要处理的但是需要时间。

4.对待信号的处理方法:1.默认2.自定义3.忽略

5.因为对于来的信号可能不能立即做出处理所以信号要保存

2.信号的产生

查看系统定义的信号列表 kill -l 

3abbc4910c694093985fb4636f6eeb85.png

1. 通过键盘产生信号

程序正在运行时我们可以通过键盘向对应的进程发送信号

Ctrl + c      //向进程发送二号信号,默认动作是结束该进程

Ctrl + \       //向进程发送三号信号 ,默认动作是结束进程

2.系统调用产生信号

1.kill 向任意进程发送信号

这里通过mysignal进程向test进程发送终止信号

#include<iostream>
#include<unistd.h>
#include<signal.h>
#include<string.h>
#include<sys/types.h>
#include<cstdio> 

static void Usage(const std::string& proc)
{
    std::cout<<"\nUsage: "<<proc<<"pid signo"<<std::endl;
}
int main(int argc,char* argv[])
{
  if(argc!=3)
  {
    Usage(argv[0]);
    exit(1);
  }
  pid_t pid=atoi(argv[1]);
  int signo=atoi(argv[2]);
  int n =kill(pid,signo);     
  if(n != 0)
  {
    perror("kill");
  }
    return 0;
}

test.cpp

#include<iostream>
#include<unistd.h>
#include<sys/types.h>


int main()
{
    while(true)
    {
        std::cout<<"我是进程,我的pid是:"<<getpid()<<std::endl;
        sleep(1);
    }
    return 0;
}

d3bf7effaa5a40ea98284a1d031e34c0.png

 885f59652f5f4d7fbaad01fca62790dc.png

 2.raise() 函数 

该函数是自己的进程向自己的进程发送信号

#include<unistd.h>
#include<cstdio>
#include<signal.h>

int main()
{
    //raise()给自己发送任意信号
    int cnt = 0;
    while(cnt<=10)
    {
        printf("cnt:%d\n",cnt++);
        sleep(1);
        if(cnt>=5)
        {
            raise(3);     //kill(getpid(),signo);其实就是kill函数的封装
        }
    }
    return 0;
}

 5accdcec10264739b872ce03084771db.png

 3.abort()函数

函数会给自己发送六号信号

#include<cstdio>
#include<unistd.h>
#include<stdlib.h>

int main()
{
    int cnt = 0;
    while(cnt<=10)
    {
        printf("cnt:%d,pid:%d\n",cnt++,getpid());
        sleep(1);
        if(cnt>=5)
        {
           abort();//kill(getpid(),SIGABRT)
        }
    }
}

 c5fe3efc5bd64d9dae6829442eea2dd8.png

 3.硬件异常产生信号

信号的产生不一定要我们给进程发送,程序运行中出现导致硬件异常的时候OS会进程发送信号

int main()
{
    while(true)
    {
        cout<<"我在运行中..."<<endl;
        sleep(1);
        int a = 10;
        a/=0;
    }

    return 0;
}

6b4bcc8b643643a191489dcd3e2bf67f.png

 OS给进程发送了信号并且终止了进程,这个终止进程的行为时OS 默认的,下面用自定义函数的方法处理信号:

#include<iostream>
#include<unistd.h>
#include<signal.h>
using namespace std;


void catchSig(int signo)
{
    //自定义处理信号的方法。。。。
    cout<<"捕捉到一个信号,信号编号是:"<<signo<<endl;
    
}
int main()
{
   
    signal(SIGFPE,catchSig);
    int a = 10;
    a/=0;
    while(true)
    {
        cout<<"我在运行中..."<<endl;
        sleep(1);
    }
}

cb9633c3f8ff4b6f878d25b40cbb7c1d.png

 

运行时该进程一直收到OS发送的8号信号,这种现象该如何理解?

CPU内有很多寄存器eax,edx等,执行int a=10,a/=0;CPU内除了数据保存,还得保证运算有没有问题,所以还有状态寄存器,状态寄存器衡量这次的运算结果,10/0.相当于10乘以无穷大,结果无穷大,引起状态寄存器溢出标记位由0变成1,CPU发生了运算异常,OS得知CPU发生运算异常,就要识别异常:状态寄存器的标记位置为1,由当前进程导致的,在向目标进程发送信号,最后就终止进程了。但是收到信号的处理方法是自定义处理的,所以说进程收到信号不一定会引起进程退出。进程没有退出,则还有可能还会被调度,CPU内部的寄存器只有一份,但是寄存器中的内容属于当前进程的上下文,一旦出现异常OS没有能力去修正这个问题,所以当进程被切换的时候,就有无数次状态寄存器被保存和恢复的过程,所以每一次恢复的时候就让OS识别到了CPU内部的状态寄存器中的溢出标志位是1。所以OS就会给进程发送信号,但是进程对待信号的处理动作是我们自定义完成的,自定义代码中并没有设置结束进程,OS再次调度时看到出错的进程还没有退出,所以又发送信号,周而复始,就能看到进程一直能捕捉到8号信号。

4.软件条件产生信号

1.在之前的管道学习中两个进程通过管道进行通信的时候,如果读端不继续在管道中读取内容时,而写端还在一直往管道中写数据时,写端就会收到OS发送的13号信号,终止写端进程。

2.定时器

int main()
{

   alarm(10);
   int cnt=1;
while(true)
{
    cout<<"cnt:"<<cnt++<<endl;
    sleep(1);
}

    return 0;
}

1dff83f2fa7148af871f19b4491eae3e.png

 在这里给程序设定了一个计时器,即倒数10秒钟,时间到了之后,OS会给该进程发送14号信号,导致进程终止了。计时器的本质是软件实现的所以这里的信号的产生是由软件条件产生的。

总结:

1.上面我一直都在说OS检测到了进程xxx,所以OS给进程发送了几号信号导致进程终止了。为什么都是OS去做这些??因为OS是进程的管理者

3.如果不能及时处理信号保存到哪里? PCB中

4.如何理解OS给进程发送信号?OS直接修改进程PCB中的关于信号的位图结构


3.核心转储

man -7 signal    //详细的查看各种信号的相关信息

652f7055bcf244fb9a9fdd97b5c7bf98.png

 Term终止表正常终止,操作系统向进程发送信号后,该进程正常终止,不会作其他工作。而Core终止会做其他工作——核心转储,目的是进程崩溃后使用gdb调式时快速定位。由core类型的信号导致的进程终止运行时,将此时进程地址空间的内容以及有关进程状态的其他信息写出的一个磁盘文件。这种信息往往用于调试(事后调试)。文件名时core.12334(pid)

我使用的时云服务器,五哦一要打开core file选项

ulimit -a   //查看各种选项的最大数量

9f721fa8084448dca48669e0661a77b3.png

ulimit -c 1024  //设置文件的大小 

 编译文件时加 -g选项代表可调式,若程序运行到某一步被OS发送信号终止了,此时在当前目录下就会出现core.12334(pid)文件,然后在命令行输入gdb a.out(可执行程序的文件名),接着输入 core-file core.12334 就可以快速的定位到导致程序挂了的地方。--------事后调试。

4.信号的保存

相关概念
实际执行信号的处理动作称为信号递达
信号从产生到递达之间的状态,称为信号未决
进程可以选择阻塞某个信号
被阻塞的信号产生时将保持在未决状态,直到进程解除对此信号的阻塞,才执行递达的动作.
注意,阻塞和忽略是不同的,只要信号被阻塞就不会递达,而忽略是在递达之后可选的一种处理动作。

在进程内部要保存信号的信息,有3种数据结构与之相关的,第一个是pending表,pending表就是位图结构。进程可能在任何时候收到OS给它发送的信号,该信号可能暂时不被处理,所以需要暂时被保存,进程为了保存信号采用位图来保存,这个位图结构就是pending位图,在没有收到信号时对应的位置就是0,当进程收到信号而现在不具备处理条件时就会先将信号保存起来即在对应的位置置1.所以OS向进程发信号就是向目标进程的peding位图设置比特位,从0到1就是当前进程收到该信号,所以发信号应该是写信号,PCB属于OS内核结构,只有OS有权力修改pending位图,所以发送信号的载体只能是OS。第二个是block位图:block位图比特位的位置代表信号标号,比特位的内容代表是否阻塞了该信号。还有一个是handler_t handler[32]={0},这个就是函数指针数组,这个数组在内核中有指针指向它,这个数组称为当前进程所匹配的信号递达的所有方法,数组是有下标的,数组的位置(下标)代表信号的编号,数组下标对应的内容表示对应信号的处理方法、

ab973e77baa547e7b3fa79b0ce6feb7f.png

 收到了信号但是还没有递达,就会保存到pending表中,如果信号在block表中被阻塞了,那这个信号即使在进程可以处理信号时也不会被递达。直到该信号不被阻塞时,进程才能够对信号做出处理。一个信号还没有产生但是并不影响它先被阻塞。

信号集

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

信号集操作函数

sigset_t 类型时让用户更好的设置pending表和block表

#include <signal.h>
int sigemptyset(sigset_t *set);        //把信号集都设置为0
int sigfillset(sigset_t *set);         //把信号集都设置位1
int sigaddset (sigset_t *set, int signo);  //把特定的信号添加到信号集中
int sigdelset(sigset_t *set, int signo);   //把特定的信号从信号集中删除
int sigismember(const sigset_t *set, int signo);  //判断信号在不在信号集中

sigprocmask :读取或更改进程的信号屏蔽字(阻塞信号集)

#include <signal.h>
int sigprocmask(int how, const sigset_t *set, sigset_t *oset);
//返回值:若成功则为0,若出错则为-1

sigpending :

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

现在练习使用这些信号集函数实现用户自定义对某些信号的屏蔽并且查看屏蔽前后信号集的变化

#include<iostream>
#include<signal.h>
#include<unistd.h>
#include<vector>
using namespace std;

//#define BLOCK_SIGNAL 2
#define MAX_SIZE 31

// static vector<int> sigarr={2,3};
static vector<int> sigarr={2};   //添加要屏蔽的信号


static void show_pending(const sigset_t& pending)   //打印pending表
{
    for(int signo=MAX_SIZE;signo>=1;signo--)
    {
        if(sigismember(&pending,signo))
        {
            cout<<"1";
        }
        else
        {
            cout<<"0";

        }
    }
    cout<<endl;
}

static void myhandler(int signo)  //自定义处理信号的处理方法
{
    cout<<"捕捉到一个信号,编号是:"<<signo<<endl;
    
}
int main()
{
    for(const auto &sig : sigarr)
    {
        signal(sig,myhandler);  //对信号的自定义捕捉
    }

    sigset_t pending,block,oblock;   //pending表 ,block表,oblock表是返回的设置完block表返回设置之前的表

    // 初始化
    sigemptyset(&pending);
    sigemptyset(&block);
    sigemptyset(&oblock);
 
    //添加要屏蔽的信号    屏蔽了信号无法被递达,被保存在pending表格中
    // sigaddset(&block,BLOCK_SIGNAL);

    //方法二: 多个信号屏蔽
    for(const auto &sig : sigarr)
    {
        sigaddset(&block,sig);
    }

    //开始屏蔽并且设置到进程
    sigprocmask(SIG_SETMASK,&block,&oblock);     //选择屏蔽的方法,返回新的屏蔽信号集合,返回旧的信号屏蔽集
  

   int cnt =10;
  while(true)
  {
    //初始化s
    sigemptyset(&pending);
    //获取
    sigpending(&pending);
    //打印
    show_pending(pending);
    sleep(1);
    if(cnt-- == 0)
    {
        cout<<"恢复了信号的屏蔽动作,现在开始不屏蔽任何信号11"<<endl; // 放在之前等打印出来,因为此时还没有对信号做出恢复
        sigprocmask(SIG_SETMASK,&oblock,&block);
   }

  }

    return 0;
}

结果:

ecd0844c383240549defc7e83c754b35.png

 程序开始运行时,我们将从键盘接受的Ctrl + c 信号即2号信号进行屏蔽,这里的屏蔽值得时将对应的信号添加到block表的位图结构中,这也再次验证了一个信号还没有被接收但是并不影响在接收之前对该信号的屏蔽。程序运行时循环打印block表,此时进程没有对任何信号进行屏蔽,在键盘上对进程发送了二号信号后,二号信号的位图结构由0置为1,但是该信号并没有立即进行递达,因为我们设定好了对于该信号屏蔽的动作,等屏蔽的时间一到,进程解除了对各种信号的屏蔽动作,此时,pending表中的二号信号的位图结构是1,而block表中二号信号的位图结构是0,所以该进程就要递达二号信号,而二号信号的处理动作时我们自定义的,所以就打印出了自定义函数中的内容。

5.信号的捕捉

前面说过,信号产生的时候,信号可能不会立即处理,会在合适的时候处理。合适的时候就是从内核态返回用户态的时候进程处理,这也说明了曾经一定是先进入了内核态,最典型的就是系统调用与进程切换

1.内核态与用户态

用户代码和内核代码,平时我们自己写的代码是属于用户态的代码,但是用户态难免会访问OS的资源(getpid,waitpid…),硬件资源(比如printf,write,red…),用户自己写的代码为了访问资源必须直接或间接访问OS提供的接口,必须通过系统调用来完成访问。系统调用是OS提供的接口,而普通用户不能以用户态的身份执行系统调用,必须让自己的身份变成内核态。身份切换成内核态才能切入到内核中访问内核的资源。实际执行系统调用是进程,但是身份其实是内核。从用户态调内核态需要身份的切换,还要调OS内部的代码,所以一般系统调用比较费时间一些。我们应该尽量避免频繁调用系统调用。

进程地址空间0-3G是用户级页表,通过用户级页表映射到不同的物理空间处,进程地址空间的3-4G是内核空间,OS为了维护从虚拟到物理之间的OS级别的代码所构成的内核级映射表,开机时OS加载到内存中,OS在物理内存中只会存在一份,因此OS的代码和数据在内存中只有独一份,所以内核级页表只有一份就够了。当进程需要访问内核的数据时通过内核级页表映射到物理内存中的OS的相关代码即可。内核空间是被映射到了每一个进程的3-4G空间,每一个进程都可以通过页表映射到OS,而且每个进程看到的OS都是一样的,所以进程要访问OS的接口,其实只需要在自己的地址空间上进行跳转就可以了。

 26eb9e194ed8400ca3403abb858923be.png

2.信号的捕捉过程

通过系统调用,陷入内核,从用户态进入内核态,在内核态访问了内核的相关代码和数据后并不是直接返回用户态,陷入内核比较费时间,切入内核之后OS会做其他工作:信号的检测和信号的处理

34e49315286d47289acca2a015dd9433.png

进程的身份在转变为内核态后还要进行信号的检测,如果此时进程PCB中收到信号且没有阻塞该信号,那就会对该信号递达,此时的身份是内核态,内核态的身份比较高,如果用户自定义处理信号做出恶意操作那可能会导致系统的崩溃。所以为了安全要将身份切回到用户态再去执行对信号的处理动作,处理完成后身份再次切换到内核态,再次进行信号的检测和信号的处理,如果没有那就返回到用户态,继续代码的执行。

3.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_mask字段说明这些需 要额外屏蔽的信号,当信号处理函数返回时自动恢复原来的信号屏蔽字。
函数的第二个参数是一个结构体,该结构体的名称和函数的名称是相同的,使用的时候设置好相关的内容即可:

 练习使用该函数:

#include<iostream>
#include<signal.h>
#include<unistd.h>
using namespace std;

void Count(int cnt)
{
    while(cnt)
    {
        printf("cnt:%2d\r",cnt);
        fflush(stdout);
        cnt--;
        sleep(1);
    }
    cout<<endl;
}
void handler(int n)
{
    cout<<"get a signo:"<<n<<"正在处理中----"<<endl;
    Count(20);
}
int main()
{
    struct sigaction act,oact;
    act.sa_handler=handler;
    act.sa_flags=0;

    sigemptyset(&act.sa_mask);
    //在处理二号信号期间  也可以选择屏蔽其他的信号
    sigaddset(&act.sa_mask,3);   //处理信号期间同时屏蔽三号信号
    sigaction(SIGINT,&act,&oact);  //二号信号的英文 
    while(1) sleep(1);
    return 0;
} 

9b35daecac68428192325ed9c86834b7.png

 723062a804584265adec657f092ab12b.png

 连续向该进程发送两次二号信号和一次三号信号,通过结果可以发现程序最后的结果是执行两次自定义函数和一次三号信号的默认处理方法。进程第一次接收到二号信号时就去执行我们设定的自定义处理动作。若再次发送二号信号此时sigaction函数会导致进程屏蔽再次执行二号信号,即在该进程PCB中的pending表和block表中的二号信号的位图结构置为1,当第一次二号信号的自定义动作结束后会自动解除对二号信号的屏蔽,然后又去执行一次二号信号,此时三号信号的位图结构都为1,等二号信号处理完后又开始执行三号信号。如果信号的发送顺序是 2 3 2处理信号的顺序依旧是两次二号信号完了之后才执行三号信号。

 
 

 

 

 

 

 

 

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【Linux】进程信号 的相关文章

  • 更改 Qt OpenGL 窗口示例以使用 OpenGL 3.3

    我正在尝试更改 Qt OpenGL 示例以使用更现代的 opengl 版本 330 似乎合适 所以我做了 在 main cpp 上设置版本和配置文件 设置着色器版本 更改着色器以使用统一 它现在构建没有任何错误 但我只看到一个空白窗口 我错
  • 我如何在 C# .NET(win7 手机)中使用“DataContractJsonSerializer”读入“嵌套”Json 文件?

    我有一个问题 如果我的 json 文件看起来像这样 Numbers 45387 Words 空间桶 我可以很好地阅读它 但是如果它看起来像这样 Main Numbers 45387 Words 空间桶 某事 数字 12345 单词 克兰斯基
  • 与 Qt 项目的静态链接

    我有一个在 Visual Studio 2010 Professional 中构建的 Qt 项目 但是 当我运行它 在调试或发布模式下 时 它会要求一些 Qt dll 如果我提供 dll 并将它们放入 System32 中 它就可以工作 但
  • 指向特征矩阵的指针数组

    我在代码中使用 Eigen 的 MatrixXd 矩阵 在某个时刻我需要一个 3D 矩阵 由于 Eigen 没有三维矩阵类型 因为它仅针对线性代数进行了优化 因此我创建了一个 MatrixXd 类型的指针数组 Eigen MatrixXd
  • 时间:2019-03-17 标签:c#ThreadSafeDeepCopy

    我一直在阅读很多其他问题以及大量谷歌搜索 但我一直无法找到明确的解决方案 根据我读过的一些最佳实践 类的静态方法应该创建线程安全的 并且实例成员应该将线程安全留给消费者 我想为该类实现深度复制方法 该类本身还有其他引用类型成员 有没有什么方
  • 动态生成的控件 ID 返回为 NULL

    我可以在 Page PreInit 函数中创建动态控件 如何检索控件及其 ID 我的 C 代码用于创建动态控件之一 var btn new WebForms Button btn Text btn ID Addmore btn Click
  • 如何在 QTabWidget Qt 中展开选项卡

    我有一个QTabWidget像这个 但我想展开选项卡以 填充 整个小部件宽度 如下所示 我怎样才能做到这一点 我在用Qt 5 3 2 and Qt 创建者 3 2 1 Update 我尝试使用setExpanding功能 ui gt myT
  • 从 WebBrowser 控件 C# 获取滚动值

    我试图在 WebBrowser 控件中获取网页的 Y 滚动索引 但无法访问内置滚动条的值 有任何想法吗 对于标准模式下的 IE 使用文档类型 正如你所说 scrollTop是的财产元素 而不是 HtmlDocument htmlDoc th
  • C++ php 和静态库

    我创建了一个library a 其中包含 cpp 和 h 文件 其中包含很多类 嵌套类和方法 我想在 php 示例中包含这个静态库并尝试使用它 我想提一下 我是 php 新手 我已经在 test cpp 文件中测试了我的 libray a
  • 给出 5 个参数,但在终端中只得到 3 个参数

    我想将一个文件传递给一个c 程序 如果我在 IDE 中执行此操作 test string string lt test txt return argc 5 但在终端上我刚刚得到argc 3 看来 这是因为 什么是 lt 意思是 我正在使用
  • PHP 致命错误:未找到“MongoClient”类

    我有一个使用 Apache 的网站 代码如下 当我尝试访问它时 我在 error log 中收到错误 PHP Fatal Error Class MongoClient not found 以下是可能错误的设置 但我认为没有错误 php i
  • 将标量添加到特征矩阵(向量)

    我刚刚开始使用 Eigen 库 无法理解如何向所有矩阵成员添加标量值 假设我有一个矩阵 Eigen Matrix3Xf mtx Eigen Matrix3Xf Ones 3 4 mtx mtx 1 main cxx 104 13 error
  • 如何分析组合的 python 和 c 代码

    我有一个由多个 python 脚本组成的应用程序 其中一些脚本正在调用 C 代码 该应用程序现在的运行速度比以前慢得多 因此我想对其进行分析以查看问题所在 是否有工具 软件包或只是一种分析此类应用程序的方法 有一个工具可以将 python
  • ASP.NET MailMessage.BodyEncoding 和 MailMessage.SubjectEncoding 默认值

    很简单的问题 但我在 MSDN 上找不到答案 查找 ASP NET 将用于的默认值 MailMessage BodyEncoding and MailMessage SubjectEncoding 如果你不在代码中设置它们 Thanks F
  • 使用restsharp序列化对象并将其传递给WebApi而不是序列化列表

    我有一个看起来像的视图模型 public class StoreItemViewModel public Guid ItemId get set public List
  • 并行运行 make 时出错

    考虑以下制作 all a b a echo a exit 1 b echo b start sleep 1 echo b end 当运行它时make j2我收到以下输出 echo a echo b start a exit 1 b star
  • 使用taskkill停止Windows服务

    我需要帮助来使用 C 终止 Windows 服务 现在要终止该服务 请使用以下选项 从命令 sc queryex ServiceName 发现后PID服务的 taskkill pid 1234 exemple f 为了便于阅读 但如果您明白
  • 您是否将信息添加到每个 .hpp/.cpp 文件的顶部? [关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 创建新的 C 头文件 源文件时 您会在顶部添加哪些信息 例如 您是否添加日期 您的姓名 文件描述等 您是否使用结构化格式来存储此信息 e g F
  • 使用 QtWebEngine 将 C++ 对象暴露给 Qt 中的 Javascript

    使用 QtWebkit 可以通过以下方式将 C 对象公开给 JavascriptQWebFrame addToJavaScriptWindowObject如中所述https stackoverflow com a 20685002 5959
  • ASP.NET Core MVC 视图组件搜索路径

    在此处的文档中 https learn microsoft com en us aspnet core mvc views view components view aspnetcore 2 2 https learn microsoft

随机推荐

  • linux wget返回值_在Linux命令行上下载文件的5个wget示例

    wget是Linux命令行实用程序 广泛用于从Linux命令行下载文件 有许多选项也可用于从远程服务器下载文件 wget与浏览器窗口中的open url相同 1 使用Wget下载文件 下面的示例将从服务器下载文件到当前本地目录 wget h
  • 【单片机毕业设计】【mcuclub-dz-062】基于单片机的蓝牙语音寻物器

    最近设计了一个项目基于单片机的蓝牙语音寻物器控制系统 与大家分享一下 一 基本介绍 项目名 蓝牙语音寻物器 项目编号 mcuclub dz 062 单片机 STC89C52 功能简介 1 通过蓝牙连接主从机 当主从机配对成功后 主从机的蜂鸣
  • Java求矩形三角形圆形梯形的面积和周长小程序页面

    用java实现图形面积周长计算器 1 一个接口 public interface Shape default void GetArea 面积 default void GetPerimetter 周长 2 圆形类 import java u
  • 孟岩:什么是通证(token),通证可以干什么?

    孟岩是最早将token翻译成为通证的区块链大咖 这个翻译已经得到到了越来越人的认可 原来它叫代币 孟岩建议把它翻译成通证 以下是孟岩关于通证的注解 孟岩 柏链道捷CEO CSDN副总裁 区块链通证派代表人物 通证的本质 通证 token 可
  • 矩阵求逆操作的复杂度分析(逆矩阵的复杂度分析)

    矩阵求逆操作的复杂度分析 逆矩阵的复杂度分析 1 背景 之前写过一篇关于矩阵复杂度分析的文章 没有想到阅读人数那么多 对于IT相关人士来说 从代码层次再结合基本数学知识 就能够很好地理解矩阵的复杂度如何计算得到和分析 其中一位读者提出 矩阵
  • 现代循环神经网络-1.门控循环单元(GRU)【动手学深度学习v2】

    文章目录 1 门控循环单元 GRU 1 1 门控隐状态 A 重置门与更新门 B 候选隐状态 C 隐状态 1 2 GRU的实现 A 从零实现 B 简洁实现 1 门控循环单元 GRU GRU是一个比较新的提出来的 在LSTM之后提出 但是相比L
  • Java接口分页调用的设计

    设计一 Test void t1 int pageNo 0 int pageSize 20 int total do pageNo 调用接口 返回数据 获取总页数 total 102 System out println 第 pageNo
  • 教务管理系统遇到的问题(回答面试官提问用)

    面试官 你做这个项目遇到了什么问题 怎么解决的 我 当时写了一个接口 是关于多个用户查询的 用户有老师 学生和管理员 他们查询的有奖项和文件 奖项和文件是两张表 这造成了很多问题 第一个问题是请求参数过多 有关于文件表和奖项表判断的参数 有
  • 华为OD机试真题-过滤组合字符串【2023Q1】

    题目内容 数字0 1 2 3 4 5 6 7 8 9分别关联 a z 26个英文字母 0 关联 a b c 1 关联 d e f 2 关联 g h i 3 关联 j k l 4 关联 m n o 5 关联 p q r 6 关联 s t 7
  • G2的一些常用配置项

    gt 本文介绍下G2的一些常用配置项 Chart图表的属性 图表的属性直接在代码上介绍 可直接复制到项目上根据实际需求可以选择配置 const chart new G2 Chart container c1 必选 指定图表容器 可以传入该
  • M600Pro操作流程

    ipad平板地面站操作 1 DJI GO 检查项 飞机状态是否为 GPS 模式 且显示起飞准备完毕 2 飞行模式为 P 档 遥控器模式是否正确 遥控器电量是否充足 其他箭头指向处 为正常 电池电量 99 各电池之间差异不超过 3 4 电池电
  • winCE中采用DMA传输数据的方法

    转载请标明是引用于 http blog csdn net chenyujing1234 对于文章中有什么意见或是需要代码的可以留言联系我 1 DMA入口 DDM控制器能服务的外围设备配置信息的结构体 typedef struct BOOL
  • 单目相机测距

    提示 文章写完后 目录可以自动生成 如何生成可参考右边的帮助文档 单目相机测距 一 理论 1 像素坐标系 1 相机坐标系 1 转换到大地坐标系 二 代码实现 1 使用matlab找到相机参数 2 使用opencv进行测距 总结 一 理论 先
  • Windows 环境下 Python3 安装 cryptography

    操作系统 win7 语言 Python 3 6 包 cryptography 3 4 7 因为工作需要 需要安装python的 cryptography包 但是屡次安装失败 特总结安装过程 以供大家借鉴 1 安装Rust 初次安装 cryp
  • 数字化变革的难点和解决方式

    了解了数字化企业的特征 还不代表企业能转型成功 从互联网1 0时期开始至今 中国传统 企业数字化转型十余年 整体效果并不理想 因为在推动转型过程中面临各种由于技能不足 和机制不足交织在一起形成的固有难点 转型推进难点 1 定义不清 这是企业
  • Sqlalchemy filter与filter_by查询语法

    摘要 https www cnblogs com kaerxifa p 13391722 html 摘要2 https blog csdn net gymaisyl article details 96601798 filter与filet
  • java部署和调用智能合约

    java部署和调用智能合约 下载安装npm和solc 1 安装gcc yum install gcc gcc c 2 安装node wget https npm taobao org mirrors node v10 14 1 node v
  • java中删除文件/文件夹的3种方法

    1 通过io删除文件 通过递归逐层删除文件信息 param filePath public static void deleteFileByIO String filePath File file new File filePath Fil
  • insert oracle用法,insert into select的实际用法,insertselect

    insert into select的实际用法 insertselect INSERT INTO SELECT语句 语句形式为 Insert into Table2 field1 field2 select value1 value2 fr
  • 【Linux】进程信号

    1 理解信号 1 信号 能够识别并做出行为的一种指令 2 信号来临的时候不一定能够立即对信号做出处理 但是并不影响信号的产生 3 信号来临 gt 时间窗口 gt gt 被处理 结果是要处理的但是需要时间 4 对待信号的处理方法 1 默认2