Linux-进程控制详解(进程创建+进程终止+进程等待+进程程序替换)

1.30 Cubemx_STM32H743 SD_Card纳入文件管理系统 Cubemx_STM32H743 SD_Card纳入文件管理系统1、简介2、CubeMX配置 1、简介 和前面文章原理其实一样的。 1.29 Cubemx_STM32F429\H743 nandflash、spifalsh纳入文件管理系统 现在一并将SD卡、NandFlash、SPIFlash一并作为文件管理。 下面直接介绍SDcard,其他参考前面文章。 2、CubeMX配置 ... 阅读详情

1. 进程创建

1.1 fork

在Linux中,我们通常使用fork函数来为一个已经存在的进程创建一个新进程。而这个新创建出来的进程被称为原进程的子进程,原进程被称为该进程的父进程。

该函数其实是一个系统调用接口,原型如下:

#include <unistd.h>
pid_t fork(void);

特性:子进程会复制父进程的PCB,二者之间代码共享,数据独有,拥有各自的进程虚拟地址空间

此时可能会有一个疑问,既然代码共享,并且子进程是拷贝了父进程的PCB,虽然他们各自拥有自己的进程虚拟地址空间,但其中的数据必然是相同的(拷贝而来),并且通过页表映射到同一块物理内存中,那么又如何做到数据独有呢?答案是:通过写时拷贝技术。

写时拷贝技术:子进程创建出来后,与父进程映射访问同一块物理内存,但当父子进程当中有任意一个进程更改了内存中的数据时,会给子进程重新在物理内存中开辟一块空间,并将数据拷贝过去。 这样避免了直接给子进程重新开辟内存空间,造成内存数据冗余。换句话说,如果父子进程都不更改内存中的值,那他们二者各自的进程虚拟地址空间通过页表映射,始终是指向同一块物理内存。

正是通过这样的写时拷贝技术,才保证了父子进程代码共享但数据独有的这一特性。 对于一些小萌新来说,可能上述文字描述并不是那么直观,此处有必要上图来进一步说明一下:

如父进程中有全局变量g_val初值为10,子进程创建之后通过复制父进程的PCB,并且二者的进程虚拟地址空间通过页表映射到同一块物理内存,但如果子进程更改了g_val的值,就会在物理内存中开辟新的空间并保存属于子进程的g_val:
在这里插入图片描述

在知道了以上特性后,下面我们来认识一下fork函数的返回值,相当重要!

通过以上函数原型我们可以看到起返回值是pid_t类型,其实就是int,在内核中是通过typedef重命名过的,我们把其当做int类型即可。

如果创建子进程失败,会返回-1,是小于0的,而如果创建子进程成功,该函数则会返回俩个值,这一点和普通的函数有很大区别。它会给子进程返回0值,而给父进程返回子进程的pid(一个大于0的数),也正是通过给父子进程返回值的不同,从而我们可以使用选择语句对齐进行分流,从而让父子进程执行不同的代码,而达到我们创建子进程的某种目的。

在了解到这一点之后,我们便可以通过代码来创建子进程并且进一步验证前面说到的一些特性。

#include <stdio.h>
#include <unistd.h>

//父子进程代码共享,但数据独有
int g_val = 100;
int main()
{
    pid_t pid = fork();//创建子进程
    if(pid < 0) {
        printf("fork error!\n");
        return -1; 
    }
    else if(pid == 0) {
        //子进程
        g_val = 200;
        printf("This is Child! g_val = %d p = %p\n",g_val,&g_val);
    }
    else {
        //父进程
        sleep(1);
        printf("This is Parent! g_val = %d p = %p\n",g_val,&g_val);
    }
    return 0;
}

运行程序,得到如下结果:
在这里插入图片描述
对于这一结果感到惊讶吗?其实只要你看懂了我上面所说的内容,相信这个结果并不难理解:子进程拷贝父进程的PCB,拥有和父进程一模一样的进程虚拟地空间以及数据,但子进程将自己的g_val更改后,会在物理内存中为其重新开辟空间来存储子进程更改后的数据,而结果中看到的地址完全相同,则是因为它们仅仅是虚拟的地址空间,真正的值是存储在物理内存中的。而这时通过页表的映射,这俩个看似相同的地址已经指向了不同的物理内存。

1.2 vfork

不止可以通过fork来创建子进程,vfork也同样是用来创建子进程的系统调用函数,那么它和fork有什么区别呢?

#include <sys/types.h>
#include <unistd.h>
pid_t vfork(void);

通过函数原型我们似乎并不能看出什么端倪,的确,vfork在使用时和fork几乎没有什么区别,返回值及其含义也和fork完全相同。其和fork的区别在于,用v_fork创建出来的子进程,也是拷贝父进程的PCB,但它和父进程共享同一个进程虚拟地址空间。也就是如下图所示的这样:
在这里插入图片描述
但是我们要思考一个问题,父子进程共享同一个进程虚拟地址空间不会有问题吗?会的!会造成调用栈混乱的问题! 举个例子,如果父进程中调用Test函数首先压栈,之后子进程则调用Fun函数,由于二者共享同一个栈空间,则Fun函数也会继续压栈,但如果此时父进程的Test函数调用完毕想要返回,却发现其并不在栈顶位置,无法出栈,这不就有问题了吗?
在这里插入图片描述

那怎么解决呢?vfork采用的方案是,在其创建出子进程之后,让子进程先执行,而父进程则会阻塞,直到子进程执行完毕,父进程才会开始执行,这样就避免了调用栈混乱的问题。

但是!这个问题是解决了,可是新的问题也随之而来了呀,我们创建子进程难道不是为了让其而父进程并发的跑或者说更高效的完成一些任务吗,而现在再子进程退出前父进程什么都不能做,这难道不会影响效率吗?或者说的再直白一些,不是浪费时间吗???

不得不说,确实。可能也正是因为这些种种的缺点,vfork这个函数已然逐渐的被时代淘汰了,fork它不香吗?为什么要用vfork呢? 博主也理解不了它存在的意义…不过也罢,我们只需稍作了解,然后还是把爱全都给fork吧!
在这里插入图片描述

2. 进程终止

含义:进程终止的含义就是一个进程的退出。

进程退出的场景

  1. 程序运行完毕,从main函数中退出
    1.1 运行完毕,结果正确
    1.2 运行完毕,结果不正确
  2. 程序没有运行完毕,中途奔溃了

进程常见退出方法:

1. 正常退出:

  1. 从main函数返回
  2. 调用exit函数
  3. 调用_exit函数

2. 异常退出: Ctrl+C,信号终止等

exit函数:

#include <stdlib.h>
void exit(int status);

其中,stauts定义了进程的终止状态,由用户自己传递,父进程可以通过wait来获取该值(下边进程等待部分实操)。

_exit函数:

#include <unistd.h>
void _exit(int status);

exit和_exit俩个函数都可以退出当前进程,而二者的区别在于:exit是库函数,_exit是系统调用函数,而库函数内部封装了系统调用。 也就是说,调用exit函数最终也会调用_exit来使进程退出,只不过在其调用_exit之前,还会做一些其他的事情,如下图:
在这里插入图片描述
从上图我们可以看出,exit()与_exit()还有一个很重要的区别就是在退出前会不会刷新缓冲区。显然,前者是会刷新缓冲区的,这也是它在封装后者的基础上所增加了一些后者并不具备的功能。

代码验证如下:

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

int main()
{
  printf("我要退出了!\n");
  exit(1);
  printf("应该不会打印我了!\n");
  return 0;
}

运行以上代码,结果如下:
在这里插入图片描述
以上结果符合完全符合我们的预期,那如果使用_exit()呢?我们再试试:

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

int main()
{
  printf("我要退出了!");
  _exit(1);
  printf("应该不会打印我了!\n");
  return 0;
}

在这里插入图片描述
不是说_exit()退出时不会刷新缓冲区吗?怎么还是会打印出来呢?注意:不是bug,原因是\n(换行符)也有刷新缓冲区的作用。我们去掉\n再次执行代码就会看到我们预期的结果:
在这里插入图片描述
那如何说明一开始调用exit不是因为其内部会刷新缓冲区而不是\n的作用呢?很简单,去掉\n再试试就清楚了,肯定也是会刷新缓冲区而打印对应内容的,只不过不会换行了。这里就不在演示。

再补充一点,除了\n(换行)以及exit()函数会刷新缓冲区之外,也可以调用fflush()来强制刷新缓冲区

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

int main()
{
  printf("我要退出了!");//没有\n
  fflush(NULL);//刷新缓冲区
  _exit(1);
  printf("应该不会打印我了!\n");
  return 0;
}

在这里插入图片描述
以上结果与使用exit函数退出进程并且前一条打印语句不带\n一致,大家可以自行验证。

3. 进程等待

3.1 为什么要进程等待

之前在了解进程概念的的时候有说到过僵尸进程,如果子进程先于父进程退出,而父进程并没有关心子进程的退出状况,从而无法回收子进程的资源,就会导致子进程变成僵尸进程。

如果对信号有一定的了解,就会知道,僵尸进程一旦产生就算是kill-9这样的强杀信号都杀不掉它,因为谁也没办法杀掉一个已经死去的进程! 那怎么办呢?当时在进程概念的位置并没有提解决(避免)僵尸进程的办法,而在这个位置再次说到它,就是想来引出进程等待这个概念。进程等待的作用就是防止僵尸进程的产生!

进程等待:父进程通过进程等待的方式,回收子进程的资源,获取子进程的退出状态。

那具体如何完成进程等待呢?答:在父进程中,使用wait或waitpid接口来完成进程等待。

3.2 wait

#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *status);

返回值:成功会返回被等待进程的pid,失败则会返回-1

参数:一级指针status,它其实是个输出型参数,用于获取子进程的退出状态,如果不关心则可以设置为NULL

代码实例:

#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>

int main()
{
  pid_t pid = fork(); //创建子进程
  if(pid < 0) {
    perror("fork");
    return -1;
  }
  else if(pid == 0) {
    //子进程
    printf("I am child, my pid is %p\n", getpid());
    sleep(3);
  }
  else {
    //父进程
    printf("I am father, my pid is %p\n", getpid());
    wait(NULL); //进程等待
    printf("进程等待成功!\n");
  }
  return 0;
}

在这里插入图片描述
执行以上程序,等够成功等待使我们预期之内的,但我们还应知道的一点是,wait是一个阻塞接口,意味着它在等待子进程退出期间是阻塞在函数内部的,直到子进程退出,它获取了子进程的退出状态并回收子进程的资源,才会返回。 如果要验证以上结论,可以适当增加子进程中休眠的时间,然后使用pstack[父进程进程号] 查看调用堆栈就可以看出,这里不再进行验证。

3.3 waitpid

//头文件同wait的头文件
pid_t waitpid(pid_t pid, int *status, int options);

waitpid同样也可以被用来进行进程等待,但它较wait接口稍稍复杂一些:

返回值:

  1. 等待成功正常返回则返回被等待进程的pid
  2. 如果第三个参数options设置成了WNOHANG,而此时没有子进程退出(没有成功等待到子进程),就会返回0,而不是阻塞在函数内部
  3. 调用出错则返回-1

参数:

  1. pid,设置成-1则表示等待任意一个子进程,同wait;如果>0则表示等待一个指定的子进程,pid就是被等待子进程的进程号
  2. status,出参,获取子进程的退出状态,同wait
  3. options,可以设置为0或WNOHANG。设置为0则与wait一样,如果没有等待到子进程退出会一直阻塞;而设置为WNOHANG则表示非阻塞,如果被等待的子进程未退出,则会返回0值,成功等待到子进程则会返回被等待子进程的pid

也就是说,如果使用waitpid接口并设置options参数为WNOHANG,则未等待到子进程退出时也会立即返回,而不是阻塞,因此这种场景我们一般搭配循环来使用,以确保可以成功等待到子进程退出。

代码实例:

#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>

int main()
{
  pid_t pid = fork();
  if(pid < 0) {
    perror("fork");
    return -1;
  }
  else if(pid == 0) {
    //子进程
    printf("I am child, pid is %p\n", getpid());
    sleep(10);
  }
  else {
    printf("I am father, pid is %p\n", getpid());
    while(waitpid(pid, NULL, WNOHANG) == 0); //循环调用waitpid,直到其返回值不为0
    printf("进程等待成功!\n");
  }
  return 0;
}

运行结果:10秒之后waitpid成功等待到子进程退出而返回非0值,跳出while循环并执行后续打印语句
在这里插入图片描述
其他传参方式大家可以自行验证。

3.4 获取子进程退出信息status

我们发现,不论是wait还是waitpid都有一个出参status,而我们之前并未关心这一点,那么这里就来探讨一下如何获取子进程的退出状态吧!

之前,我们已经知道status是一个出参,由操作系统为其赋值,用户可以传递NULL值表示不关心,而如果传入参数,操作系统就会根据该参数,将子进程的退出信息反馈给父进程,由status最终被赋予的值来体现。

那么,到底如何通过status来获取子进程的退出信息呢,要知道这一点,我们必须先知道status的使用细节:

status是一个int类型的值,意味着它应该有32个比特位,但它又不能被当初普通的整形来看待,因为其高16位的值并不被使用,而只使用其低16个比特位:
在这里插入图片描述
那么,在只关心其低16位的基础上,具体的比特位又分别代表什么含义呢,也就是如何通过这低16个比特位来获取子进程的退出信息呢,我们同样通过俩张图来解释:

子进程正常退出时:
在这里插入图片描述
子进程异常退出时:
在这里插入图片描述
图片表达应该更加直观一些,不过还是要稍作解释:可以看出,不论是正常退出还是异常退出,status的高8个比特位(只讨论低16个比特位)都表示子进程的退出码,而这个退出码一般是return的返回值或者exit的参数;正常退出时,status的低8个比特位为全0;而异常退出时,其第8个比特位则为core dump标志位,用来标志是否会有core dump文件产生,而低7个比特位则是退出信号。

我们可以分别通过以位运算的方式来分别得到以上信息:

退出码:(status >> 8) & 0xFF

低7位(检测子进程是否异常退出):status & 0x7F

  • 结果为0则表示正常退出
  • 不为0则说明是异常退出,因为有终止信号

core dump标志位:(status >> 7) & 0x1

  • 结果为0则表示没有core dump产生
  • 等于1则说明有core dump产生

通过代码来进一步验证以上结论:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>

int main()
{
  pid_t pid = fork();
  if(pid < 0) {
    perror("fork");
    return -1;
  }
  else if(pid == 0) {
    //子进程
    printf("I am child, pid is %p\n", getpid());
    sleep(3);
    exit(20); //退出子进程并将其退出码设置为20
  }
  else {
    printf("I am father, pid is %p\n", getpid());
    int status; //定义status,让操作系统为其赋值
    waitpid(-1, &status, 0); //这种传参方式的waitpid和wait几乎没有区别
    printf("进程等待成功!\n");
    //低7位为全0则表示正常退出
    if((status & 0x7F) == 0) {
      printf("正常退出!\n");
      printf("exitcode = %d\n", (status >> 8) & 0xFF);
    }
    else {
      printf("异常提出!\n");
      printf("core dump flag = %d\n", (status >> 7) & 0x1);
    }
  }
  return 0;
}

运行结果:
在这里插入图片描述

4. 进程程序替换

原理:进程程序替换其实是替换当前正在运行程序的代码段和数据段,并更新堆栈信息。

有关进程虚拟地址空间以及根据页表映射至物理内存这一模式大家都已经非常熟悉了,这里就不再画图解释。我们需要知道的是,进程程序替换与fork不同,它并不会创建新的进程,而是该进程的用户空间代码和数据完全被新程序替换,从新程序的启动例程开始执行。替换前后的进程号并未改变。

4.1 exec函数簇

我们一般通过替换函数来完成进程程序替换,也就是exec函数簇,需要注意的是,它并不是一个函数,而是多个函数。他们都以exec开头,统称exec函数,其函数原型如下:

#include <unistd.h>

int execl(const char *path, const char *arg, ...);
int execlp(const char *file, const char *arg, ...);
int execle(const char *path, const char *arg,..., char * const envp[]);
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
int execvpe(const char *file, char *const argv[],char *const envp[]);

首先说返回值

  • 这些函数如果调用成功则加载新的程序从启动代码开始执行,不再返回。
  • 如果调用出错则返回-1
  • 所以exec函数只有出错的返回值而没有成功的返回值

参数解释

path/file:要替换的可执行程序的名称,path需要带路径
arg/argv[]:可执行程序的参数,规定其第一个参数必须是可执行程序的名称,并以NULL结尾表示参数传递完毕,二者的区别在于参数是以可变参数列表还是字符数组的方式给出
envp[]:程序员自己组织的环境变量,以数组的方式给出,内部同样需要以NULL结尾,如果传入NULL则认为当前程序没有环境变量

如果以上描述还不是很好理解,那么我们可以再仔细观察下这些函数的区别,可以发现,除了开头都是exec这一共同点之外,其余字母无非就是l或v的区别、有没有p的区别以及有没有e的区别:

l或v的区别

  • l表示命令行参数为可变参数列表,传参数时需要以NULL结尾
  • v表示命令行参数为指针数组,由程序员自己提供

有没有p的区别:是否会去搜索环境变量

  • 有p则代表会去环境变量PATH去搜索当前要替换程序所在的位置
  • 没有p则意味着不会去搜索环境变量,需要程序员自己提供想要替换的程序所在的路径

有没有e的区别:是否需要程序员自己组织环境变量

  • 没有e则表示不需要程序自己组织环境变量,内核会将当前的环境变量继承下来
  • 有e则代表需要程序员自己组织环境变量,如果直接传递NULL则表示当前程序没有环境变量;如果自己组织环境变量,则指针数组中得到环境变量需要以NULL结尾

代码实战:

#include <stdio.h>
#include <unistd.h>

int main()
{
    printf("下面进行进程替换!\n");

    //将当前程序替换为ls程序
    execl("/usr/bin/ls","ls","-l",NULL); //l表示命令行以可变参数列表的形式给出,没有p则说明需要带路径,没有e说明不需要自己组织环境变量

    //如果进程替换成功,下面的代码将不再执行
    printf("继承替换失败!\n");

    return 0;
}

在这里插入图片描述
上述代码以execl为例简单的演示了进程程序替换的实际效果,也完全符合我们的预期,其他函数大家可以自己尝试,都非常的简单。

还需要补充的一点就是:如果使用man去查看这些函数,会发现他们都在3号手册,也就是库函数所在的手册,意味着上述的exec函数簇其实本身都是库函数,而非系统调用。其实,不论是哪个函数,它们最终都会去调用一个叫做execve的系统调用函数,从而真正完成进程程序替换。

#include <unistd.h>
int execve(const char *filename, char *const argv[], char *const envp[]);

不仅如此,而这些函数内部,其实也是相互调用的逻辑,不过最终都还是会去调用execve来完成进程程序替换:
在这里插入图片描述
文章到这里就结束了,如果感觉博主写的还行的话,就点个赞吧~

华为od 面试八股文_操作系统_01_含答案 阅读详情

相关推荐

通信原理 | python调制识别数据及代码

数据集包含了从-20dB 到+18dB 总共 20 个信噪比(步长为 2)下的 11 种调制信号, 包括 AM-DSB、 AM-SSB 和 WBFM 三种模拟调制信号,以及 BPSK、 QPSK、 8PSK、 CPFSK、 GFSK、 PAM4、 QAM16 和 QAM64 八种数字调制信号。其中信号的中心频率为 200KHz,采样频率为 1Msamp/s,且每个信噪比下每种调制信号包含 1000 个信号。其中每个信号包含 IQ 两路数据,且每一路数据都包含有 128 个采样点。

若北辰 1713

(论文速读)EDiT:用线性压缩注意力加速扩散 Transformer

本文提出了一种高效扩散Transformer架构EDiT,通过创新的线性压缩注意力机制解决传统DiT在生成高分辨率图像时的计算瓶颈。EDiT采用卷积增强的线性注意力(ConvFusion+SpatialCompressor)处理图像自注意力,同时为多模态场景设计混合注意力方案,仅对图像-图像交互进行线性化处理,保留文本相关交互的标准注意力。实验表明,EDiT在PixArt-Σ和Stable Diffusion3.5-Medium上实现高达2.2倍的加速,同时保持接近原始模型的生成质量。该方法的核心创新在于针

LJ1147517021的博客 384

SAP生产订单技术性完成(TECO)操作指南与实战应用

生产订单技术关闭操作指南主要包括单笔和批量关闭两种方式,通过CO02/COHV事务码完成。

m0_47402127的博客 1885

B2B企业AI搜索可见度诊断与GEO技术优化实践:从0%到67%的架构重构之路

B2B采购的AI化是趋势,而是已经发生的现实。确保品牌被写进AI的大脑。用中立监测工具做一次AI可见度体检,定位品牌在12+模型中的存在感盲区;将官网从“展示窗口”重构为“AI信源”,重点改造信息架构、FAQ体系和资质事实页;建设企业知识库,统一多信源口径,为AI提供高置信度的引用素材。今天做,明天你的客户就会被AI推荐到竞品那里。技术团队应抓住当前窗口期,用工程化手段解决AI可见度问题。

daydayup0931的博客 334

ChatGPT生成的pdf怎么导出 只要加个“AI导出鸭”

摘要: 本文探讨了ChatGPT生成内容导出为PDF时的格式问题,分析了公式乱码、排版错乱等痛点,对比了四种主流导出方案的优劣。研究发现,直接复制粘贴格式损失严重,Pandoc虽效果最佳但操作复杂。文章提出需要标准化"AI原生→版式文档"转译层,并介绍了"AI导出鸭"小程序的工程化解决方案——通过构建AST解析层和对接PDF渲染引擎,实现一键高保真导出,平均耗时仅23秒,格式保真度达9.2/10,已服务超3万次导出请求。

aidssxz的博客 729

8.4 处理智能体的工具调用与输出解析《LangGraph开发AI Agent实践》

规范遵循:工具需遵循LangChain的BaseTool接口,定义清晰的name、description以及args_schema(通常为Pydantic模型)。注册方式:将工具实例传入LLM的tools参数(如OpenAI的function_calling)或通过LangGraph的状态节点显式绑定。目的:确保LLM能理解工具的功能、输入格式及使用场景。

夏天又到了的专栏 558

Codex 实战:用 AI 写运维脚本

如果发现数字提取有误,可以继续在会话中让 Codex 调整 awk 逻辑,例如“状态码只匹配三位数组成的字段,且只取每行第一个符合条件的字段”。AI 写运维脚本的收益,在某一两个脚本上,而在你形成的**“明确描述需求 + 快速验证馈”的工程习惯**。这是一个非常典型的日志分析任务,用 Shell 的 grep、awk 就能完成,但字段位置容易写错,正好适合用 Codex 来生成。理解这三者的关系,能解释很多看似“稳定”的现象:同样的需求,换个说法、少给一段上下文,结果可能完全同。

2601_96492900的博客 270

企业级AI Agent规模化落地的技术挑战:从62%试点到23%规模化的差距在哪?

数据显示,62%的企业已完成AI Agent试点,但成功实现规模化部署的比例仅为23%。从“Demo跑通”到“生产级落地”之间,隔着一系列工程化难题:任务执行可靠性、遗留系统兼容、数据安全合规、状态管理与断点恢复、多租户隔离。本文从技术架构角度逐一拆解这些挑战,并给出可落地的解决方案。

2501_93684580的博客 417

织信开发日志 17:织信 Skill 的目的,是把平台能力交给 AI Agent

织信 Skill 的核心价值,是让 AI 说得更像产品经理,也是让 AI 写出更漂的需求文档。 它的价值是把织信的平台能力变成 AI Agent 可调用的工具集。

iori97king的专栏 723

STEPONMOON的人工智能之旅(一)

《AI入门第一课:破除三大误解》 本文从日常生活切入,指出AI已渗透输入法、推荐系统等场景,既非神秘黑箱,也非科幻机器人。针对大众对AI的两种极端认知——"万能神"或"铁疙瘩",作者提出核心观点:AI本质是"从数据中找规律的程序"。全文通过四部分展开:首先建立学习动机,随后逐一拆解"AI=机器人""AI有自我意识""AI超越人类"三大常见误解,最后引导读者建立理性认知框架。文中配有场景插图

qq_36115196的博客 222

BERT预训练原理详解:MLM掩码预测 + NSP句子预测

介绍 BERT 预训练的 MLM 掩码语言模型、NSP 下一句预测两项自监督任务,分析任务实现细节与存在问题,梳理 BERT 预训练流程、下游微调方法以及 RoBERTa、ALBERT 等变体模型的核心改进

weixin_44021329的博客 514

PDF论文处理器 - 完整使用指南

PDF论文处理器是一个专门为网安科研论文设计的PDF文本分割工具,旨在将英文论文PDF文件转化为Dify知识库可直接使用的高质量数据块。

XLYcmy的博客 526

国产AI算力芯片,到了真正实战检验的时刻

1361亿砸向内蒙古草原,赌的已经再是概念,而是一条正在闭环的产业链。图1:2026绿色算力(人工智能)大会开幕式现场8月22日,呼和浩特敕勒川草原,500多人坐进千人会议中心,参加2026绿色算力(人工智能)大会。这场由呼和浩特市政府主办、中国信通院参与承办的大会,集中签约13个项目,总投资额1361亿元。我们看一下签约名单:火山引擎的GW级算力园区落在乌兰察布,寒武纪把芯片实验室落进呼和浩特,海悟的算力装备产业园、协鑫能科的算电协同一体化项目、中国电信数据中心同步落地。

张星河的博客 426

AI、机器学习与深度学习到底在讲什么

AI 是一个目标,ML 是达成目标的主流方法,DL 是 ML 里效果最好的一类算法,而 大模型 是 DL 在数据和参数规模放大之后的产物。

2302_81805546的博客 596

2026AI智能体培训机构客观测评|零基础到进阶全方位择校指南

随着人工智能技术快速迭代,AI智能体已实现规模化产业落地,凭借自主决策、任务编排、工具调用、工程化部署等核心能力,广泛应用于多行业场景,成为技术从业者重点学习的热门方向。目前市面上AI智能体学习平台参差齐,课程定位、教学体系差异较大。本文结合2026年行业技术标准与课程现状,对主流学习平台进行中立客观测评,划分同学习适配维度、整理标准化择校依据,为零基础、进阶学习者提供科学的学习择校参考。

AIkk86的博客 196

溯引 GEO 优化系统落地实战指南

很多制造业老板最近都在焦虑:明明产品过硬,价格也有优势,但在客户用 AI 助手搜索“哪家工厂做精密加工靠谱”时,跳出来的全是贸易公司或者知名的小作坊,自家品牌连影子都看到。这种“隐形”状态在传统的搜索引擎时代还能靠 SEO 慢慢熬,但在生成式 AI 主导的问答场景下,一旦模型知识库里没有你的权威数据,你就等于在数字世界里“存在”了。这仅仅是流量流失的问题,更是品牌话语权的旁落。对于源头工厂而言,AI 问答再是简单的信息检索,而是直接决定采购决策的“信任背书”。

2601_95351996的博客 226

AI Agent 在数据分析领域的落地判断:哪些场景真的需要 Agent

数据分析领域的 Agent,最大陷阱是「能力够」,而是**「能力用错了地方」**。真正能落地的 Agent,从来是替代整条数据流水线,而是在可校验、可观察、可恢复的边界内,解决那些「路径固定、需要边走边看」的探索性问题。把确定性留给 SQL 和规则,把确定性交给 Agent,才是当前阶段最务实的工程判断。与其问「我的团队能能上 Agent」,如改问一个更具体的问题:**你手头那个场景上,Agent 能比一句 SQL 多解决什么?**想清楚这个答案,落地判断就已经完成了一大半。

2501_94116301的博客 391

钉钉AI服务商+专属AI一体机+算力本地部署一体化实战:从“数据敢上公有云”到“算力数据库到Agent应用一站式本地化落地

以专属AI一体机承载全部算力与数据。以钉钉AI服务商身份完成应用集成。以本地化部署守住数据合规底线。这套方案的核心价值在于:企业既获得了大模型能力,又保住了数据主权。对于有数据合规要求、又希望深度使用AI的企业,这是一条值得参考的落地路径。

Pi210301的博客 417

【DOA估计】四根天线、一块SDR,神经网络把测向误差压进2度以内【附python代码】

基于射频信号的测向与定位,是雷达、通信、无人系统里绕开的基础能力。但真正把算法搬到室外、搬进室内,问题就来了:多径传播。 一个信号经墙面、地面射后,接收端会同时看到直达径和若干条延迟副本,它们在角度上彼此靠近、在能量上此消彼长。以 MUSIC 为代表的子空间类算法在这种场景下的表现并理想:一方面,协方差矩阵估计需要足够多的快拍数,快拍足时噪声子空间泄露,谱峰位置漂移;另一方面,弱信号体制下(比如远距离 LoRa 终端),MUSIC 的角度分辨率明显下降,甚至给出虚假谱峰。传统思路是加阵元、加快拍、

m0_54016576的博客 432

图像处理入门017 | 图像格式转换与批量处理 pipeline

图像处理算法入门系列 | 2026-08-26(周三)关键词:cv2.imwrite、JPEG quality、PNG compression、WEBP、批量格式转换、CLI pipeline。

专注:太空算力、AI infra、异构调度、大模型成本工程 435

2026‑08‑24 AI产业深度解读|算力涨价潮、Hugging Face寻求出售、AI训练版权诉讼、模型溯源争议

梳理8月24日对AI研发人员高价值产业动态:覆盖英伟达高端AI服务器涨价传闻、Hugging Face被曝探索出售、Twitch训练数据集体诉讼、OpenAI AI网络攻击安全预警、开源模型溯源知识产权争议;每条附带工程视角解读、收益与现实约束;适合大模型后端、开源生态、Agent安全、AI产品研发人员。关键词AI服务器涨价;训练数据版权;Agent安全;开源模型知识产权;

分享日常学习生活 520

windriver 12.21(64位)

windriver安装包,绝对可靠好用,64位系统,可以下载下来试试。

基于python的立体匹配基础算法SSD、SAD、ZNCC、BM、SGBM实现

基于python的立体匹配基础算法SSD、SAD、ZNCC、BM、SGBM实现

上一篇: vector的模拟实现(思路清晰+注释详细=包你能看懂+学会)
丶阿部
博客等级 码龄7年 47粉丝 30原创
评论 16
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值