Linux应用程序开发:进程的一些事儿

news2024/12/23 20:27:43

目录

  • 一、进程的简介
    • 1、什么是进程,进程的概念
    • 2、进程状态
    • 3、什么是进程号
    • 4、进程间的通信方法(IPC)
  • 二、 fork()创建子进程
  • 三、父、 子进程间的文件共享
    • 1、实验1
    • 2、实验2
  • 四、使用execl函数执行新程序
  • 五、关于终端上对进程的一些指令操作
  • 六、孤儿进程
  • 七、僵尸进程
    • 1、监视子进程
  • 八、守护进程
    • 1、何为守护进程
    • 2、编写守护进程程序
  • 九、进程间的通信方法实现
    • 1、管道通信
      • ①无名管道通信
      • ②有名管道通信
    • 2、信号通信
      • 信号的目的是用来通信的
      • 信号由谁处理、怎么处理
      • 信号是异步的
      • ①信号的分类
        • Ⅰ、可靠信号与不可靠信号:
        • Ⅱ、实时信号与非实时信号:
      • ②信号的发送函数及使用测试实验
        • Ⅰ、raise()函数
        • Ⅱ、kill()函数
        • Ⅱ、alarm()函数
      • ③信号的接收函数及使用测试实验
        • Ⅰ、pause()函数
      • ④信号的处理函数及使用测试实验
        • Ⅰ、signal()函数
    • 3、共享内存、消息队列、信号量更新中...

一、进程的简介

1、什么是进程,进程的概念

  进程是一个动态过程,而非静态文件,它是程序的一次运行过程,当应用程序被加载到内存中运行之后它就称为了一个进程,当程序运行结束后也就意味着进程终止,这就是进程的一个生命周期。

2、进程状态

  Linux 系统下进程通常存在 6 种不同的状态,分为:就绪态、运行态、僵尸态、 可中断睡眠状态(浅度睡眠)、不可中断睡眠状态(深度睡眠)以及暂停态。
  ⚫ 就绪态(Ready) : 指该进程满足被 CPU 调度的所有条件但此时并没有被调度执行,只要得到 CPU就能够直接运行;意味着该进程已经准备好被 CPU 执行,当一个进程的时间片到达,操作系统调度程序会从就绪态链表中调度一个进程;
  ⚫ 运行态: 指该进程当前正在被 CPU 调度运行,处于就绪态的进程得到 CPU 调度就会进入运行态;
  ⚫ 僵尸态: 僵尸态进程其实指的就是僵尸进程,指该进程已经结束、但其父进程还未给它“收尸”;
  ⚫ 可中断睡眠状态: 可中断睡眠也称为浅度睡眠,表示睡的不够“死”,还可以被唤醒,一般来说可以通过信号来唤醒;
  ⚫ 不可中断睡眠状态: 不可中断睡眠称为深度睡眠,深度睡眠无法被信号唤醒,只能等待相应的条件成立才能结束睡眠状态。把浅度睡眠和深度睡眠统称为等待态(或者叫阻塞态) ,表示进程处于一种等待状态,等待某种条件成立之后便会进入到就绪态;所以,处于等待态的进程是无法参与进程系统调度的。
  ⚫ 暂停态: 暂停并不是进程的终止,表示进程暂停运行,一般可通过信号将进程暂停,譬如 SIGSTOP信号;处于暂停态的进程是可以恢复进入到就绪态的,譬如收到 SIGCONT 信号。一个新创建的进程会处于就绪态,只要得到 CPU 就能被执行。以下列出了进程各个状态之间的转换关系,如下所示:
在这里插入图片描述

3、什么是进程号

  Linux 系统下的每一个进程都有一个进程号(process ID,简称 PID),进程号是一个正数,用于唯一标
识系统中的某一个进程。

4、进程间的通信方法(IPC)

  ①管道通信:分别为有名管道和无名管道。
  ②信号。
  ③共享内存。
  ④消息队列。
  ⑤信号量。
  ⑥套接字(socket)。

二、 fork()创建子进程

在这里插入图片描述

三、父、 子进程间的文件共享

  调用 fork()函数之后,子进程会获得父进程所有文件描述符的副本,这些副本的创建方式类似于 dup(),
这也意味着父、子进程对应的文件描述符均指向相同的文件表,如下图所示:
在这里插入图片描述

  由此可知,子进程拷贝了父进程的文件描述符表,使得父、子进程中对应的文件描述符指向了相同的文件表, 也意味着父、子进程中对应的文件描述符指向了磁盘中相同的文件,因而这些文件在父、子进程间实现了共享,譬如,如果子进程更新了文件偏移量,那么这个改变也会影响到父进程中相应文件描述符的位置偏移量。

1、实验1

  父进程打开文件之后,然后 fork()创建子进程,此时子进程继承了父进程打开的文件描述符(父进程文件描述符的副本) ,然后父、子进程同时对文件进行写入操作。
在这里插入图片描述
  上图测试结果可知,此种情况下,父、子进程分别对同一个文件进行写入操作,结果是接续写,不管是父进程,还是子进程,在每次写入时都是从文件的末尾写入, 很像使用了 O_APPEND 标志的效果。 其原因也非常简单, 图 9.6.1 中便给出了答案,子进程继承了父进程的文件描述符,两个文件描述符都指向了一个相同的文件表,意味着它们的文件偏移量是同一个、绑定在了一起,相互影响,子进程改变了文件的位置偏移量就会作用到父进程,同理,父进程改变了文件的位置偏移量就会作用到子进程。

2、实验2

  父进程在调用 fork()之后,此时父进程和子进程都去打开同一个文件,然后再对文件进行写入操作。
在这里插入图片描述
  上图测试结果可知,这种文件共享方式实现的是一种两个进程分别各自对文件进行写入操作,因为父、子进程的这两个文件描述符分别指向的是不同的文件表,意味着它们有各自的文件偏移量,一个进程修改了文件偏移量并不会影响另一个进程的文件偏移量,所以写入的数据会出现覆盖的情况。

四、使用execl函数执行新程序

  当子进程的工作不再是运行父进程的代码段,而是运行另一个新程序的代码,那么这个时候子进程可以通过 exec 函数来实现运行另一个新的程序。而execl函数是exec族函数里面的其中一个员,但它是比较常使用的那个。
  1、先创建新的程序hello.c文件。
在这里插入图片描述
  2、创建一个execl.c文件,功能:创建子进程,并且将子进程继承的父进程的程序替换成新的程序,并运行。
在这里插入图片描述
  上图测试现象可知,execl函数是可以替换子进行的程序,然后执行新的程序的。

五、关于终端上对进程的一些指令操作

  指令:ps -aux
  其功能是查看系统进程的详细信息。

  指令: | grep
  其功能是管道筛选信息。

  指令:kill -9 [pid]
  其功能是杀死,结束对应进程。

六、孤儿进程

  父进程先于子进程结束,也就是意味着,此时子进程变成了一个“孤儿”,我们把这种进程就称为孤儿进程;因为子进程在结束后需要父进程将子进程的一些资源释放掉,而父进程先于子进程结束的话,那么系统就会让init进程接管父进程职责,释放结束后的子进程资源。 在 Linux 系统当中,所有的孤儿进程都自动成为 init 进程(进程号为 1)的子进程, 换言之,某一子进程的父进程结束后,该子进程调用 getppid()将返回 1, init 进程变成了孤儿进程的“养父”。

  孤儿进程程序实现与测试:
在这里插入图片描述
  由上图测试结果可知,在红色框框中,父进程还未结束;在黄色框框中,由于子进程sleep阻塞了3秒,父进程先于子进程结束了,然后子进程的父进程(pid=10604)变成了父进程(pid=2122),在右边框框可知,pid:2122是/sbin/upstart其实就是init进程。

七、僵尸进程

  进程结束之后,通常需要其父进程为其“收尸”,回收子进程占用的一些内存资源,父进程通过调用wait()(或其变体 waitpid()、 waitid()等)函数回收子进程资源,归还给系统。
  如果子进程先于父进程结束,此时父进程还未来得及给子进程“收尸”,那么此时子进程就变成了一个僵尸进程。 子进程结束后其父进程并没有来得及立马给它“收尸”, 子进程处于“曝尸荒野”的状态,在这么一个状态下,我们就将子进程成为僵尸进程;至于名字由来,肯定是对电影情节的一种效仿!
  当父进程调用 wait()(或其变体,下文不再强调)为子进程“收尸”后,僵尸进程就会被内核彻底删除。另外一种情况,如果父进程并没有调用 wait()函数然后就退出了,那么此时 init 进程将会接管它的子进程并自动调用 wait(), 故而从系统中移除僵尸进程。
  如果父进程创建了某一子进程,子进程已经结束,而父进程还在正常运行,但父进程并未调用 wait()回收子进程,此时子进程变成一个僵尸进程。 首先来说,这样的程序设计是有问题的,如果系统中存在大量的僵尸进程,它们势必会填满内核进程表,从而阻碍新进程的创建。需要注意的是,僵尸进程是无法通过信号将其杀死的,即使是“一击必杀”信号 SIGKILL 也无法将其杀死,那么这种情况下,只能杀死僵尸进程的父进程(或等待其父进程终止),这样 init 进程将会接管这些僵尸进程,从而将它们从系统中清理掉!所以,在我们的一个程序设计中,一定要监视子进程的状态变化,如果子进程终止了,要调用 wait()将其回收,避免僵尸进程。

  僵尸进程程序实现与测试:
在这里插入图片描述
  通过命令可以查看到子进程 10997 依然存在,可以看到它的状态栏显示的是“Z”(zombie,僵尸),表示它是一个僵尸进程。 僵尸进程无法被信号杀死,大家可以试试,要么等待其父进程终止、要么杀死其父进程,让 init 进程来处理,当我们杀死其父进程之后,僵尸进程也会被随之清理。

1、监视子进程

  在很多应用程序的设计中,父进程需要知道子进程于何时被终止,并且需要知道子进程的终止状态信息,是正常终止、还是异常终止亦或者被信号终止等,意味着父进程会对子进程进行监视。而这可以通过系统调用 wait()以及其它变体来监视子进程的状态改变。

  wait()函数:
  对于许多需要创建子进程的进程来说,有时设计需要监视子进程的终止时间以及终止时的一些状态信息,在某些设计需求下这是很有必要的。 系统调用 wait()可以等待进程的任一子进程终止,同时获取子进程的终止状态信息,其函数原型如下所示:
在这里插入图片描述
在这里插入图片描述

  使用wait函数监视子进程程序实现与测试:
在这里插入图片描述
  实验现象可知,父进程也是经过2秒的等待后才进行对子进程收尸处理的,说明wait()函数能起到监视和减少子进程变成僵尸进程发生。

八、守护进程

1、何为守护进程

  守护进程(Daemon) 也称为精灵进程,是运行在后台的一种特殊进程,它独立于控制终端并且周期性地执行某种任务或等待处理某些事情的发生, 主要表现为以下两个特点:
  ⚫ 长期运行。 守护进程是一种生存期很长的一种进程,它们一般在系统启动时开始运行,除非强行终止,否则直到系统关机都会保持运行。 与守护进程相比,普通进程都是在用户登录或运行程序时创建,在运行结束或用户注销时终止,但守护进程不受用户登录注销的影响,它们将会一直运行着、直到系统关机。
  ⚫ 与控制终端脱离。 在 Linux 中,系统与用户交互的界面称为终端,每一个从终端开始运行的进程都会依附于这个终端,这是上一小节给大家介绍的控制终端,也就是会话的控制终端。当控制终端被关闭的时候, 该会话就会退出, 由控制终端运行的所有进程都会被终止, 这使得普通进程都是和运行该进程的终端相绑定的; 但守护进程能突破这种限制,它脱离终端并且在后台运行, 脱离终端的目的是为了避免进程在运行的过程中的信息在终端显示并且进程也不会被任何终端所产生的信息所打断。
  守护进程是一种很有用的进程。 Linux 中大多数服务器就是用守护进程实现的,譬如, Internet 服务器inetd、 Web 服务器 httpd 等。同时,守护进程完成许多系统任务,譬如作业规划进程 crond 等。
  守护进程 Daemon,通常简称为 d,一般进程名后面带有 d 就表示它是一个守护进程。守护进程与终端无任何关联,用户的登录与注销与守护进程无关、不受其影响,守护进程自成进程组、自成会话,即pid=gid=sid。通过命令"ps -ajx"查看系统所有的进程,如下所示:
在这里插入图片描述
  TTY 一栏是问号?表示该进程没有控制终端,也就是守护进程,其中 COMMAND 一栏使用中括号[]括起来的表示内核线程,这些线程是在内核里创建,没有用户空间代码,因此没有程序文件名和命令行,通常采用 k 开头的名字,表示 Kernel。

2、编写守护进程程序

  编写守护进程一般包含如下几个步骤:
  1) 创建子进程、终止父进程
  父进程调用 fork()创建子进程,然后父进程使用 exit()退出,这样做实现了下面几点。第一,如果该守护进程是作为一条简单地 shell 命令启动,那么父进程终止会让 shell 认为这条命令已经执行完毕。第二,虽然子进程继承了父进程的进程ID,但它有自己独立的进程ID,这保证了子进程不是一个进程组的组长进程,这是下面将要调用 setsid 函数的先决条件!
  2) 子进程调用 setsid 创建会话
  这步是关键,由于之前子进程并不是进程组的组长进程,所以调用 setsid()会使得子进程创建一个新的会话,子进程成为新会话的首领进程,同样也创建了新的进程组、子进程成为组长进程,此时创建的会话将没有控制终端。 所以这里调用 setsid 有三个作用:让子进程摆脱原会话的控制、让子进程摆脱原进程组的控制和让子进程摆脱原控制终端的控制。在调用 fork 函数时,子进程继承了父进程的会话、进程组、控制终端等,虽然父进程退出了,但原先的会话期、进程组、控制终端等并没有改变,因此,那还不是真正意义上使两者独立开来。 setsid 函数能够使子进程完全独立出来,从而脱离所有其他进程的控制。
  3) 将工作目录更改为根目录
  子进程是继承了父进程的当前工作目录,由于在进程运行中,当前目录所在的文件系统是不能卸载的,这对以后使用会造成很多的麻烦。因此通常的做法是让“/”作为守护进程的当前目录,当然也可以指定其它目录来作为守护进程的工作目录。
  4) 重设文件权限掩码 umask
  文件权限掩码 umask 用于对新建文件的权限位进行屏蔽。由于使用 fork 函数新建的子进程继承了父进程的文件权限掩码,这就给子进程使用文件带来了诸多的麻烦。因此, 把文件权限掩码设置为 0, 确保子进程有最大操作权限、这样可以大大增强该守护进程的灵活性。设置文件权限掩码的函数是 umask,通常的使用方法为 umask(0)。
  5) 关闭不再需要的文件描述符
  子进程继承了父进程的所有文件描述符, 这些被打开的文件可能永远不会被守护进程(此时守护进程指的就是子进程,父进程退出、子进程成为守护进程) 读或写,但它们一样消耗系统资源,可能导致所在的文件系统无法卸载,所以必须关闭这些文件, 这使得守护进程不再持有从其父进程继承过来的任何文件描述符。
  6) 将文件描述符号为 0、 1、 2 定位到/dev/null
  将守护进程的标准输入、标准输出以及标准错误重定向到/dev/null,这使得守护进程的输出无处显示、也无处从交互式用户那里接收输入。
  7) 其它:忽略 SIGCHLD 信号
  处理 SIGCHLD 信号不是必须的, 但对于某些进程,特别是并发服务器进程往往是特别重要的,服务器进程在接收到客户端请求时会创建子进程去处理该请求,如果子进程结束之后,父进程没有去 wait 回收子进程,则子进程将成为僵尸进程;如果父进程 wait 等待子进程退出,将又会增加父进程的负担、也就是增加服务器的负担,影响服务器进程的并发性能,在 Linux 下,可以将 SIGCHLD 信号的处理方式设置为SIG_IGN,也就是忽略该信号,可让内核将僵尸进程转交给 init 进程去处理,这样既不会产生僵尸进程、又省去了服务器进程回收子进程所占用的时间。
在这里插入图片描述

  从上图可知, daemon进程成为了一个守护进程,与控制台脱离,当关闭当前控制终端时,daemon进程并不会受到影响,依然会正常继续运行;
  守护进程可以通过终端命令行启动,但通常它们是由系统初始化脚本进行启动,譬如/etc/rc*或/etc/init.d/*等。

补充知识点:
在这里插入图片描述

九、进程间的通信方法实现

1、管道通信

①无名管道通信

  pipe无名管道通信只能作用在有亲缘关系的进程之间通信,详情如下图所示:
在这里插入图片描述
  pipe是一种单向数据传输的管道,其参数pipefd[2]是个整形数组,而pipefd[0]和pipefd[1]分别是创建的读管道的文件描述符和写管道的文件描述符。

  使用pipe函数实现父进程与子进程间的通信及测试:
在这里插入图片描述
  从上图可知,当子进程读管道数据时,如果管道没有数据就会一直阻塞。只有管道有数据可读,子进程才会通,如下图所示:
在这里插入图片描述
  在父进程中向管道写入数据,然后子进程向管道读取数据。

②有名管道通信

  mkfifo有名管道通信可以作用在无亲缘关系的进程之间通信,详情如下图所示:
在这里插入图片描述
  mkfifo其实就是创建了一个实实在在的fifo文件,然后进程间的通信就是通过对创建的fifo文件进行操作,其fifo文件和块设备文件一样,都是不占用字节的,如下图所示:
在这里插入图片描述

  使用mkfifo函数实现两个无亲缘关系的进程间的通信及测试:
  读fifo数据的进程程序:
在这里插入图片描述
  写fifo数据的进程程序:
在这里插入图片描述
  现象:
在这里插入图片描述

2、信号通信

  信号的基本概念:信号是事件发生时对进程的通知机制,也可以把它称为软件中断。信号与硬件中断的相似之处在于能够打断程序当前执行的正常流程, 其实是在软件层次上对中断机制的一种模拟。 大多数情况下,是无法预测信号达到的准确时间,所以,信号提供了一种处理异步事件的方法。

信号的目的是用来通信的

  一个具有合适权限的进程能够向另一个进程发送信号,信号的这一用法可作为一种同步技术,甚至是进程间通信(IPC)的原始形式。 信号可以由“谁”发出呢? 以下列举的很多情况均可以产生信号:
  ⚫ 硬件发生异常,即硬件检测到错误条件并通知内核,随即再由内核发送相应的信号给相关进程。硬件检测到异常的例子包括执行一条异常的机器语言指令,诸如,除数为 0、数组访问越界导致引用了无法访问的内存区域等,这些异常情况都会被硬件检测到,并通知内核、然后内核为该异常情况发生时正在运行的进程发送适当的信号以通知进程。
  ⚫ 用于在终端下输入了能够产生信号的特殊字符。 譬如在终端上按下 CTRL + C 组合按键可以产生中断信号(SIGINT),通过这个方法可以终止在前台运行的进程;按下 CTRL + Z 组合按键可以产生暂停信号(SIGCONT),通过这个方法可以暂停当前前台运行的进程。
  ⚫ 进程调用 kill()系统调用可将任意信号发送给另一个进程或进程组。 当然对此是有所限制的,接收信号的进程和发送信号的进程的所有者必须相同,亦或者发送信号的进程的所有者是 root 超级用户。
  ⚫ 用户可以通过 kill 命令将信号发送给其它进程。 kill 命令想必大家都会使用,通常我们会通过 kill命令来“杀死”(终止)一个进程,譬如在终端下执行"kill -9 xxx"来杀死 PID 为 xxx 的进程。 kill命令其内部的实现原理便是通过 kill()系统调用来完成的。
  ⚫ 发生了软件事件,即当检测到某种软件条件已经发生。 这里指的不是硬件产生的条件(如除数为 0、引用无法访问的内存区域等),而是软件的触发条件、触发了某种软件条件(进程所设置的定时器已经超时、进程执行的 CPU 时间超限、进程的某个子进程退出等等情况)。
  进程同样也可以向自身发送信号,然而发送给进程的诸多信号中,大多数都是来自于内核。
  以上便是可以产生信号的多种不同的条件,总的来看,信号的目的都是用于通信的,当发生某种情况下,通过信号将情况“告知”相应的进程,从而达到同步、通信的目的。

信号由谁处理、怎么处理

  信号通常是发送给对应的进程,当信号到达后, 该进程需要做出相应的处理措施,通常进程会视具体信号执行以下操作之一:
  ⚫ 忽略信号。也就是说,当信号到达进程后,该进程并不会去理会它、直接忽略,就好像是没有出该信号,信号对该进程不会产生任何影响。事实上,大多数信号都可以使用这种方式进行处理,但有两种信号却决不能被忽略,它们是 SIGKILL 和 SIGSTOP,这两种信号不能被忽略的原因是:它们向内核和超级用户提供了使进程终止或停止的可靠方法。另外,如果忽略某些由硬件异常产生的信号,则进程的运行行为是未定义的。
  ⚫ 捕获信号。 当信号到达进程后,执行预先绑定好的信号处理函数。为了做到这一点,要通知内核在某种信号发生时,执行用户自定义的处理函数,该处理函数中将会对该信号事件作出相应的处理,Linux 系统提供了 signal()系统调用可用于注册信号的处理函数。
  ⚫ 执行系统默认操作。 进程不对该信号事件作出处理,而是交由系统进行处理,每一种信号都会有其对应的系统默认的处理方式。需要注意的是,对大多数信号来说,系统默认的处理方式就是终止该进程。

信号是异步的

  信号是异步事件的经典实例,产生信号的事件对进程而言是随机出现的,进程无法预测该事件产生的准确时间,进程不能够通过简单地测试一个变量或使用系统调用来判断是否产生了一个信号,这就如同硬件中断事件,程序是无法得知中断事件产生的具体时间,只有当产生中断事件时,才会告知程序、然后打断当前程序的正常执行流程、跳转去执行中断服务函数,这就是异步处理方式。


  信号本质上是 int 类型数字编号,这些信号在<signum.h>头文件中定义, 每个信号都是以 SIGxxx 开头,这里就自己去查了。


①信号的分类

Ⅰ、可靠信号与不可靠信号:

  不可靠信号主要指的是进程可能对信号做出错误的反应以及信号可能丢失(处理信号时又来了新的信号,则导致信号丢失)。
  在 Linux 系统下使用"kill -l"命令可查看到所有信号,如下所示:
在这里插入图片描述
  括号" ) "前面的数字对应该信号的编号,编号 1~31 所对应的是不可靠信号,编号 34~64 对应的是
可靠信号,从图中可知,可靠信号并没有一个具体对应的名字,而是使用了 SIGRTMIN+N 或 SIGRTMAXN 的方式来表示。

Ⅱ、实时信号与非实时信号:

  实时信号与非实时信号其实是从时间关系上进行的分类,与可靠信号与不可靠信号是相互对应的, 非实时信号都不支持排队,都是不可靠信号;实时信号都支持排队,都是可靠信号。 实时信号保证了发送的多个信号都能被接收, 实时信号是 POSIX 标准的一部分,可用于应用进程。

②信号的发送函数及使用测试实验

Ⅰ、raise()函数

  可以在终端中敲man 3 raise可知raise函数的功能,如下图所示:
在这里插入图片描述
  由上图可知,raise(sig)等价于kill(getpid(), sig),也就是说其功能就是自己给自己发送信号(实质是先将信号和pid号发给内核,内核再发送该信号给对应的pid进程或直接处理)。
  这里我做一个简单自己杀死自己的实验,如下图所示:
在这里插入图片描述

Ⅱ、kill()函数

  这里不过多介绍该函数了,可以在man手册查询。
  这里我做一个简单 “进程kill” 杀死手动指定的 “进程a” 的实验,如下图所示:
在这里插入图片描述
在这里插入图片描述

Ⅱ、alarm()函数

  这里不过多介绍该函数了,可以在man手册查询。
  这里我做一个简单闹钟定时程序,当时间到了发出闹钟时间就终止程序的实验,如下图所示:
在这里插入图片描述

③信号的接收函数及使用测试实验

Ⅰ、pause()函数

  pause()系统调用可以使得进程暂停运行、进入休眠状态,直到进程捕获到一个信号为止,详细信息可以可以在man手册查询。
  这里我做一个简单闹钟定时使程序退出pause状态,这次闹钟程序不是用默认的信号处理函数,当时间到了发出闹钟时间就触发pause函数,让程序继续往下走,如下图所示:
在这里插入图片描述

④信号的处理函数及使用测试实验

Ⅰ、signal()函数

  当进程接收到内核或用户发送过来的信号之后,根据具体信号可以采取不同的处理方式:忽略信号、捕获信号或者执行系统默认操作。
  忽略信号:
在这里插入图片描述
  系统默认:
在这里插入图片描述
  捕获信号:
在这里插入图片描述

3、共享内存、消息队列、信号量更新中…

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

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

相关文章

AI绘图风格对照表/画风样稿详细研究记录及经验总结(分析Midjourney和Stable Diffusion风格提示词实际使用情况)不断更新中...

Midjourney和Stable Diffusion都可以通过输入文本生成出令人惊叹的AI图像。 Midjourney是一个收费的在线服务&#xff0c;通过discord对话的形式来生图&#xff0c;局限性较大&#xff0c;但由于后台官方模型做得好&#xff0c;因此出图效果非常完美&#xff1b; Stable Diffus…

3.Spring Security实现JWT token验证

目录 1. Spring Security详细介绍 2. Spring Security详细使用 3. Spring Security实现JWT token验证 4. JWT&#xff08;JSON Web Token&#xff0c;JSON令牌&#xff09; 5. Spring Security安全注解 Spring Security实现JWT token验证 Spring Security是Spring提供的一…

图数据库

1 前言 图数据结构&#xff0c;能够很自然地表征现实世界。比如用户、门店、骑手这些实体可以用图中的点来表示&#xff0c;用户到门店的消费行为、骑手给用户的送餐行为可以用图中的边来表示。使用图的方式对场景建模&#xff0c;便于描述复杂关系。在美团&#xff0c;也有比较…

超全实战操作详解合集——阿里云ECS服务器(CentOS 7.8 64位)安装rpm格式jdk、tomcat8、mysql8三件套

一、下载rpm格式的jdk 网上自行下载下载jdk&#xff0c;使用Xftp连接Linux主机&#xff0c;将jdk文件放入任意目录下&#xff08;为方便后续操作&#xff0c;重命名为1.rpm&#xff09; 二、安装jdk 进入存放jdk文件的目录&#xff0c;使用命令yum -y install 1.rpm 进行安装…

前端工具 Prettier 详细使用流程(兼容ESLint)

一、简介 中文文档&#xff0c;英文官网。 Prettier 是一个开箱即用的代码格式化程序。用来批量处理旧代码的统一&#xff0c;涉及引号、分号、换行、缩进等。支持目前大部分语言处理&#xff0c;包括 JavaScript、Flow、TypeScript、CSS、SCSS、Less、JSX、Vue、GraphQL、JSO…

【计算机视觉】华为天才少年谢凌曦:关于视觉识别领域发展的个人观点!

文章目录 一、前言二、CV的三大基本困难和对应研究方向三、以下简要分析各个研究方向3.1 方向1a&#xff1a;神经网络架构设计3.2 方向1b&#xff1a;视觉预训练3.3 方向2&#xff1a;模型微调和终身学习3.4 方向3&#xff1a;无限细粒度视觉识别任务 四、在上述方向之外五、结…

“踏浪”自动驾驶量产潮,商业化加速的知行科技奔赴IPO

今春过半&#xff0c;自动驾驶产业链扎堆上市的情况在延续&#xff0c;一位新的重量级选手加入了这场热潮。 4月4日&#xff0c;自动驾驶领域领先的解决方案提供商知行汽车科技(苏州)股份有限公司&#xff08;即“知行科技”&#xff09;&#xff0c;向港交所递交招股书&#…

全网多种方法解决error: failed to push some refs to ‘xxx‘

文章目录 1. 复现错误2. 分析错误3. 解决错误4. 解决该错误的其他方法 1. 复现错误 今天使用git status查看文件状态&#xff0c;发现有一个文件未提交&#xff0c;如下代码所示&#xff1a; D:\project\test>git status On branch master Your branch is up to date with …

【剑指offer】学习计划day1

目录 一. 前言 二. 用两个栈实现队列 a.题目 b.题解分析 c.AC代码 二. 包含min函数的栈 a.题目 b.题解分析 c.AC代码 一. 前言 本系列是针对Leetcode中剑指offer学习计划的记录与思路讲解。详情查看以下链接&#xff1a; 剑指offer-学习计划https://leetcode.cn/study-pla…

Java八大基本数据类型

Java八大基本数据类型 byteshortintlongfloatdoublebooleanchar byte byte数据类型是8位、有符号的&#xff0c;以二进制补码表示的整数 最小值是-128&#xff08;-2^7&#xff09;&#xff1b; 最大值是127&#xff08;2^7-1&#xff09;; 默认值是0&#xff1b; byte类型用在…

stm32读写内部Flash

stm32内部flash地址架构映射 因为我的stm32f407的内部flash是1M的所以块2不存在&#xff0c;但他的地址仍然存在&#xff0c;只是没有作用&#xff0c;这是stm32的整体框架。 主存储器 一般我们说 STM32 内部 FLASH 的时候&#xff0c;都是指这个主存储器区域&#xff0c;它…

duilib窗口拖动

直接使用如下就可以了&#xff0c;不用再使用继承。 LRESULT CXmlWnd::OnNcHitTest(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) {POINT pt;RECT rcClient;RECT rcCaption;CControlUI * pControl NULL;rcCaption m_P…

C++练级之初级:第五篇

C练级之初级&#xff1a;第五篇 第五篇 C练级之初级&#xff1a;第五篇1.auto关键字2.for循环改进3.指针空值nullptr4.内联函数4.1内联函数的概念4.2内联函数的注意点 总结 1.auto关键字 &#x1f914;什么是auto(automatic的缩写&#xff0c;自动的意思)关键字&#xff1f; au…

OpenShift 4 - 在 CI/CD Pipeline 中创建 KubeVirt 容器虚拟机 - 方法1+2 (视频)

《OpenShift / RHEL / DevSecOps 汇总目录》 说明&#xff1a;本文已经在支持 OpenShift 4.12 的 OpenShift 环境中验证 文章目录 准备环境安装可实现 KubeVirt 操作的 Tekton 资源创建密钥对 在 CI/CD 流水线管道中创建 VM方法1&#xff1a;通过 Manifest 任务创建 VM方法2&am…

如何实现Spring AOP以及Spring AOP的实现原理

AOP:面向切面编程,它和OOP&#xff08;面向对象编程)类似。 AOP组成: 1、切面:定义AOP是针对那个统一的功能的&#xff0c;这个功能就叫做一个切面&#xff0c;比如用户登录功能或方法的统计日志&#xff0c;他们就各种是一个切面。切面是有切点加通知组成的。 2、连接点:所有可…

ClickHouse快速入门

目录 1 ClickHouse介绍1.1 ClickHouse 的特点1.1.1 列式存储1.1.2 DBMS 的功能1.1.3 多样化引擎1.1.4 高吞吐写入能力1.1.5 数据分区与线程级并行1.1.6 性能对比 2 数据类型2.1 整型2.2 浮点型2.3 布尔型2.4 Decimal 型2.5 字符串2.6 枚举类型2.7 时间类型2.8 数组 3 表引擎3.1…

SpringBoot tomcat核心参数

server.tomcat.threads.min-spare10server.tomcat.threads.max200server.tomcat.max-connections8192server.tomcat.accept-count100 第一个参数代表程序启动就会开启10个线程。 如果我改成20个&#xff0c;看看什么情况&#xff0c;可以看到初始化了20个线程 看第二个参数&am…

2022年中国云市场份额:阿里云腾讯云下降

我是卢松松&#xff0c;点点上面的头像&#xff0c;欢迎关注我哦&#xff01; 4月23日&#xff0c;IDC发布《中国公有云服务市场(2022下半年)跟踪》&#xff0c;占据前四的分别为阿里云(40.6%)、华为云(11.0%)、腾讯云(11.0%)、中国电信(8.7%)。咱们说重点&#xff0c;如下图所…

DFMEA 在车用燃料电池空压机设计中的应用

摘要&#xff1a; DFMEA在空压机研发中的应用 氢气具有资源丰富、热值高和无污染等特点&#xff0c;因而是燃料电池汽车最理想的二次能源。空压机作为燃料电池汽车的关键总成&#xff0c;掌握其核心部件的设计和制造技术非常必要。应用传统的设计方法进行相关零部件如空气轴承…

D3.js(2) Data-Join

什么是Data-Join&#xff1f; 本质上是将数据与图元绑定 可以省去大量根据数据设置图元属性的代码量&#xff0c;对动态变化的数据提供统一接口 D3.js绑定数据的三个状态 Enter 数据数量>图元数量&#xff0c;d3.js会根据新增的数据生成相应的图元 给不存在数据绑定的图…