Linux - 进程控制

Linux - 进程控制

一、进程创建

在 Linux 系统中,创建进程通常通过 fork() 系统调用实现。fork() 会创建一个新的进程,称为子进程,它与父进程共享几乎所有的资源(如文件描述符、环境变量等),但具有独立的地址空间。子进程最初的内容是父进程的精确副本。

fork详细见Linux - 进程.md

二、进程等待

1) 进程等待的必要性

在 Linux 系统中,进程等待是父进程为了管理和回收子进程资源所采取的一种机制。这种机制的重要性主要体现在以下几个方面:

  • 防止僵尸进程:当子进程结束后,内核会保留其退出状态等信息,直到父进程读取为止。如果父进程不等待并收集这些信息,子进程的资源无法完全释放,导致形成僵尸进程。僵尸进程虽然不再占用 CPU,但仍然保留进程表项,占用内存资源。过多的僵尸进程会导致系统进程表满溢,影响系统的资源分配。

  • 释放内存,避免资源泄漏:僵尸进程残留的内存、描述符等资源没有释放,可能逐渐累积而造成内存泄漏。尽管进程退出时大部分内存会被内核回收,但某些操作系统资源,尤其是内核管理表项,需要父进程通过等待机制显式回收。

  • 获取子进程的执行状态和结果:父进程可以通过等待机制获取子进程的退出状态信息,如子进程是否正常退出、是否有错误发生等。这对于多进程应用尤为重要,父进程可以根据子进程的执行结果来决定下一步操作。例如,在多任务并发的服务器中,父进程可以检查子进程是否成功处理了请求。

2) 进程等待接口(wait

pid_t wait(int *wstatus)是一个用于进程控制的系统调用,它让父进程暂停执行,直到某个子进程结束并且回收该子进程的状态信息。通常,wait() 用于防止产生僵尸进程(zombie processes),并获取子进程的退出状态。

  • status 是一个指向整数的指针,用于存储子进程的退出状态。如果你不关心子进程的退出状态,可以将其设置为 NULL。(详见后面的waitpid

  • 返回值:

    • 如果成功,wait() 返回已终止的子进程的 PID。
    • 如果发生错误,返回 -1,并设置 errno

工作原理:

  • 父进程调用 wait() 后,会阻塞,直到子进程终止。也就是说,父进程会被挂起,直到子进程结束并返回它的状态。
  • 一旦子进程终止,父进程将收到其终止的通知,并可以通过 status 参数查看子进程的退出状态。
  • 子进程在退出时会发送一个终止信号给父进程,父进程通过调用 wait() 接收这个信号并回收子进程资源,防止子进程变为僵尸进程。

3) 进程等待接口(waitpid

pid_t waitpid(pid_t pid, int *wstatus, int options)是 Linux 和类 Unix 系统中的一个系统调用,它与 wait() 类似,但比 wait() 更加灵活和可控。waitpid() 允许父进程等待一个特定的子进程,或者控制等待行为的方式。它是 wait() 的一个增强版本。

  • pid_t pid:这是父进程希望等待的子进程的进程 ID(PID)。

    • pid > 0:等待指定 PID 的子进程。如果指定的 PID 是当前进程的子进程,则 waitpid() 会阻塞直到该子进程退出。
    • pid == 0:等待任何与调用进程在同一进程组中的子进程。
    • pid == -1:等待任何子进程,等同于 wait()
    • pid < -1:等待指定进程组中的任何子进程(pid 取值的绝对值指定了进程组 ID)。
  • int *status:这是一个指向整数的指针,用于存储子进程的退出状态。状态信息可以通过一些宏来解码,如 WIFEXITED()WEXITSTATUS()WIFSIGNALED() 等。如果 statusNULL,则父进程不会获取子进程的状态信息。 status由32个bit位构成,不同bit表示不同信息:

    • 高 8 位(位 31-24):这是用于标识子进程是否因为信号而终止的信息。
    • 中间的 7 位(位 23-17):这些位通常用于标识一些系统特定的细节,如进程是否因特定的信号被暂停、是否为僵尸进程等。
    • 低 16 位(位 15-0):这些位用于存储子进程的退出码(退出状态),具体根据子进程的退出方式(正常退出、信号终止等)有所不同。

    对于status的低16位:

    • 如果程序正常退出,低七位全零(表示子进程成功退出),高八位表示进程退出状态,存储子进程的退出状态码(子进程的exit()、return的结果)。
    • 如果程序因信号终止,低七位会包含导致子进程终止的信号编号,高八位无用。

    WIFEXITED(status):Wait IF EXITED

    • 系统提供的宏,对应!(status & 0x7F),判断是否正常退出。

    WEXITSTATUS(status):Wait EXITSTATUS

    • 系统提供的宏,对应(status>>8) & 0x7F,获取退出码。
  • int options:这是一个控制等待行为的标志参数。常见的选项包括:

    • 0: 无设置。
    • WNOHANG:如果没有子进程退出,则不阻塞,立即返回。
    • WUNTRACED:如果子进程处于暂停状态(由信号停止),也会返回。
    • WCONTINUED:如果子进程因 SIGCONT 信号被恢复执行,也会返回。
    • WEXITSTATUS(status)WTERMSIG(status) 等宏依然可以用于检查状态。
  • 返回值:

    • 子进程已退出:返回值是子进程的 PID,父进程可以通过 status 获取子进程的退出状态。
    • 子进程尚未退出:返回 0,如果设置了 WNOHANG 选项且没有子进程退出。
    • 错误:返回 -1,并且会设置 errno 以指示发生了什么错误。

waitpid()wait() 的区别:

  • 灵活性waitpid() 允许父进程选择等待特定的子进程,而不是默认等待任何子进程。通过设置 pid 参数,父进程可以选择等待某个子进程,或等待一组子进程,或等待任何子进程(pid == -1)。

  • 非阻塞等待waitpid() 支持 WNOHANG 选项,可以让父进程在没有任何子进程退出时不阻塞,立即返回。wait() 没有类似的选项,它总是会阻塞,直到至少有一个子进程退出。

  • 返回信息waitpid() 可以通过 status 返回子进程的退出状态,并且可以选择是否处理子进程的状态信息。如果不关心退出状态,status 可以设置为 NULL

  • 选择性控制waitpid() 提供了更多的选项(如 WUNTRACEDWCONTINUED),使得父进程可以更精确地控制等待的行为。

4) 非阻塞轮询(Non-blocking Polling):

指在程序中,使用轮询技术来检查某个条件或事件是否发生,但与阻塞方式不同,非阻塞轮询不会让程序停下来等待事件的发生,而是通过不断地检查条件或事件的状态,如果事件没有发生,程序会继续执行其他任务,或者以某种方式休息再继续检查。

waitpidoption参数设置为WNOHANG选项时,waitpid() 会检查子进程的状态,如果子进程已经退出,它会返回子进程的状态;如果子进程还没有退出,它会立即返回而不会让父进程阻塞。这使得父进程可以在等待子进程结束时继续做其他事情,而不是停下来等待。通过和循环代码的结合就能完成非阻塞轮询。

  • 非阻塞轮询的基本原理:

    • 轮询:轮询是一种周期性检查某些条件或事件是否发生的技术。例如,在某些资源或输入设备的情况下,程序通过定期检查它们的状态来了解是否发生了某些变化。

    • 非阻塞:与阻塞的不同之处在于,阻塞操作会让程序停下来等待条件发生,直到它返回结果。而非阻塞操作不会让程序停止,它会立即返回,无论条件是否满足。

    • 在非阻塞轮询中,程序会在循环中不断检查某个状态(例如输入数据是否准备好,或者某个文件是否可用),而不会被阻塞或进入等待状态。如果条件未满足,程序通常会继续做其他工作,或者以某种方式推迟再次检查的时间。

  • 典型应用场景:

    • 网络编程:在网络编程中,非阻塞IO通常用于检查数据是否可读或可写,而不让程序被等待阻塞。比如使用select()poll()epoll()等技术,可以在多个网络连接上轮询,处理已就绪的连接。
    • 事件驱动编程:在GUI应用程序或服务器程序中,非阻塞轮询常用于检查用户输入或网络事件。如果没有事件发生,程序可以继续处理其他任务,而不会被卡住等待某个事件的发生。
    • 设备轮询:在嵌入式系统中,硬件设备(如传感器或外部设备)的状态常常以非阻塞方式进行轮询。设备驱动程序在不停地检查设备状态,获取数据或者处理中断。

三、进程程序替换

1)替换原理

在 UNIX 和 Linux 系统中,进程程序替换是指进程调用 exec 系列函数,将当前的程序代码、数据、堆栈等完全替换为新程序的内容。替换的核心原理在于,新程序的代码和数据加载到当前进程的地址空间中,而保留进程的标识信息(如 PID)。以下是进程程序替换的详细原理:

  • 地址空间清理与重建

    • 当进程调用 exec 时,操作系统会清空当前进程的地址空间,包括代码段、数据段、BSS 段和堆栈段。

    • 接着,新的可执行程序会根据其段信息(如代码段、数据段等)加载到进程的虚拟地址空间中,覆盖掉旧的内容。

  • 进程 ID 不变

    • exec 只是替换进程的内容,而不生成新的进程,因此不会改变当前进程的 PID。

    • 这意味着 exec 调用前后的 PID 是相同的,使得进程可以保持其在系统中的唯一标识。

  • 文件描述符继承

    • 大多数文件描述符会被保留(除非设置了 close-on-exec 标志),使新程序可以继续使用现有的文件描述符,如标准输入、标准输出等。

    • 这种机制让 exec 非常适用于 shell 等程序,它们通常需要将输入和输出重定向给新进程。

  • 资源的重新分配与初始化

    • 旧程序的动态内存(如堆)、信号处理器等在替换过程中会被释放或重置。新程序从起始位置(main 函数)开始执行,并根据新的初始化代码配置自身的运行环境。

    • 系统资源如环境变量会在地址空间重建后重新载入。

  • 保留父子关系

    • 替换程序后,进程的父子关系不变。父进程可以继续监控和等待子进程的状态,从而获得新程序的执行结果或退出码。
  • 重新开始执行

    • exec 完成后,进程从新程序的入口点(通常是 main 函数)开始执行。旧程序的内容已不复存在,当前进程完全成为了一个新程序的执行体。
  • exec系列函数只有执行失败才有返回值,执行成功时没有返回值。

  • 程序替换中,环境变量不会被替换

2) 程序替换接口

程序替换接口指的是 exec 系列函数,用于将当前进程的地址空间替换为新程序的地址空间。调用 exec 函数后,当前进程的代码段、数据段、堆栈段等将被新程序替换,并从新程序的入口开始执行,其本质是一个代码级别的加载器。exec 系列函数的主要接口如下:

  • execl - 以可变参数形式传递程序参数。

    int execl(const char *path, const char *arg, ...)

    execl("/bin/ls", "ls", "-l", NULL);
    
  • execlp - 自动在 PATH 中查找可执行文件,以可变参数形式传递程序参数。

    int execlp(const char *file, const char *arg, ...)

    execlp("ls", "ls", "-l", NULL);
    
  • execle - 以可变参数形式传递程序参数,并指定环境变量。

    int execle(const char *path, const char *arg, ..., char *const envp[])

    // 自定义环境变量
    char *envp[] = { "MYVAR=hello", "PATH=/bin:/usr/bin", NULL };
    execle("/bin/ls", "ls", "-l", NULL, envp);
    // 直接用系统调用environ
    execle("/bin/ls", "ls", "-l", NULL, environ);
    
  • execv - 以数组形式传递程序参数。

    int execv(const char *path, char *const argv[])

    char *args[] = {"ls", "-l", NULL}; 
    execv("/bin/ls", args);
    
  • execvp - 自动在 PATH 中查找可执行文件,以数组形式传递程序参数。

    int execvp(const char *file, char *const argv[]);

    char *args[] = {"ls", "-l", NULL}; 
    execvp("ls", args);
    
  • execve - 以数组形式传递程序参数,并指定环境变量(底层实现,其他接口都基于此函数)。

    int execve(const char *path, char *const argv[], char *const envp[])

    char *args[] = {"ls", "-l", NULL}; 
    char *envp[] = { "MYVAR=hello", "PATH=/bin:/usr/bin", NULL };
    execve("/bin/ls", args, envp);
    
  • exec 系列函数中,字母 lv 表示参数传递方式的不同:

    • l (list):参数以可变参数列表的形式逐个传递,类似于 execlexeclp。在这种形式中,程序参数依次列出,最后需要用 NULL 表示结束。例如,execl("/bin/ls", "ls", "-l", NULL);

    • v (vector):参数以数组(向量)的形式传递,类似于 execvexecvp。参数数组是一个以 NULL 结尾的指针数组,每个元素指向一个参数字符串。例如,execv("/bin/ls", args);,其中 argschar *args[] = {"ls", "-l", NULL};

  • 有了程序替换(通过 exec 系列函数实现)就可以实现跨语言调用程序。这是因为在程序替换后,进程会从一个全新的程序开始运行,而不受先前语言或环境的限制。这种机制使得用一种编程语言编写的程序能够启动并运行其他语言编写的程序。

  • 当调用传递环境变量的exec时,是彻底替换,而不是新增。如果想新增可以用如下实现:

    putenv("MYVALUE=123456")
    execle("/bin/ls", "ls", "-l", NULL, environ);
    
  • man 手册中查找 execve 函数时,可能会发现它并不在 man exec 的描述中,而是在 man execve 这一条目中有详细记录。这是因为 execve 是底层的、系统直接调用的一个接口函数。而其他 exec 函数(如 execlexecvp 等)都是基于 execve 实现的包装函数。通过分开记录,便于提供系统调用的独立说明。

四、进程中止

1) 退出场景

程序的退出场景通常有以下几种情况:

  • 正常退出:程序按预期执行完毕后结束,返回错误码 0,表明一切正常。
  • 错误退出:代码执行完毕但结果不符合预期,通常返回一个非零错误码。这个错误码可以帮助父进程判断错误原因。
  • 异常终止:进程由于未捕获的信号(如分段错误)或其他致命错误被系统强制终止。
  • 进程结束本质上可能是代码没有跑完,此时我们不关心退出码,而是关注为什么异常和发生了什么异常。因此我们对于程序的正常判断应当先判断代码是否异常,然后判断代码是否正常退出。

  • 进程退出时的PCB会包含退出信息,在父进程调用waitpid时,其输出参数status就会根据子进程PCB内的保存的退出信息得到对应信息,从而将子进程的退出信息交给父进程。

2) 退出码

**退出码(Exit Code)**是指一个程序在结束运行时返回给操作系统的整数值,用于描述程序的终止状态。这些值通常用来指示程序的执行结果、是否遇到了错误、甚至具体的错误原因。退出码可以帮助操作系统、脚本、或其他程序了解运行结果,并决定下一步要做什么。

int main() {printf("process\n");exit(0); // 返回退出码0,由父进程接收。
}
  • echo $?

    查询最近的退出码。

    # ? 里保存了最近的退出码内容,echo $? 就查询了其中的内容。
    (base) Raizeroko@bciserver:~/code$ echo $?
    0
    
  • char *strerror(int errnum)

    strerror 是一个标准 C 库函数,用于将错误代码转换为对应的错误消息字符串。该函数的常见用法是将系统调用或库函数返回的错误代码(通常保存在 errno 中)转化为人类可读的描述信息。

    # ls访问不存在的文件时,本质是其main返回了退出码2,并打印了对应的错误信息
    (base) Raizeroko@bciserver:~/code$ ls test.txt
    ls: 无法访问 'test.txt': 没有那个文件或目录
    (base) Raizeroko@bciserver:~/code$ echo $?
    2
    
  • errno

    errno 是一个全局变量,用于存储最近一次系统调用或标准库函数的错误代码。每当函数调用失败时(返回 -1NULL),通常会设置 errno 以标识出错的具体原因。errno 是标准 C 库的一部分,在操作系统和编程中非常常见,用来帮助程序判断和处理错误情况。

3) 常见退出方法

  • return: 在 main 函数结束时return一个状态码,用于表示进程执行状态。main函数的返回值本质表示进程运行完成时是否是正确的结果,如果不是,可以用不同的退出码表示不同的出错原因。

  • exit(int status):该函数进行清理工作(如刷新文件缓冲区,关闭文件描述符等),然后返回退出码,供父进程查询。

  • _exit(int status):立即终止进程,跳过清理工作,直接释放进程资源,通常用于 fork 后的子进程在执行 exec 失败后的快速退出。

_exit()exit()的区别:

  • 调用用户注册的清理函数:

    • exit通过 atexit() 注册的退出处理函数。程序中每次调用 atexit() 注册的函数会在进程退出时自动调用,顺序为“后注册的先执行”(LIFO 顺序)。这些函数可以用于执行一些特定的清理操作,如释放资源、输出日志等。
    • _exit不进行操作。
  • 刷新,关闭所有标准 I/O 流的缓冲区:

    • exit确保所有 stdoutstderr 等缓冲区中的数据都被写入目标文件或显示设备中,以避免丢失数据。
    • _exit不进行操作。
  • 应用场景不同:

    • exit 适合在一般情况下正常退出,确保资源和 I/O 缓冲得到妥善处理。
    • _exit适用于需要快速终止进程的场景,如 fork() 后的子进程遇到错误时。

本质上_exit是被exit所调用的关系,只不过库j给予了我们能调_exitexit两个接口的选择

4) 异常终止

进程的异常终止确实本质上是因为收到了某种信号。信号(Signal)是操作系统用来通知进程发生异步事件的一种机制,例如非法操作、用户干预等。当进程收到这些信号并无法处理时,就会被系统终止。典型的异常终止信号包括:

  • SIGKILL (9):强制终止信号,直接由内核处理,不允许进程捕获或忽略,进程会立即终止。例如通过 kill -9 [PID] 发出的信号。
  • SIGTERM (15):请求终止信号,通常用于程序的正常关闭。程序可以捕获该信号并在退出前执行清理操作。
  • SIGSEGV (11):段错误信号,通常因进程试图访问无效内存地址引发,例如访问空指针或越界访问。
  • SIGINT (2):来自键盘的中断信号,通常由用户按下 Ctrl+C 触发,允许进程捕获并决定如何处理。
  • SIGABRT (6):由 abort() 函数引发的信号,通常用于异常终止程序,例如发生了严重错误时。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

.NET 10首个预览版发布:重大改进与新特性概览!

前言 .NET 团队于2025年2月25日发布博文&#xff0c;宣布推出 .NET 10 首个预览版更新&#xff0c;重点改进.NET Runtime、SDK、Libraries 、C#、ASP.NET Core、Blazor 和.NET MAUI 等。 .NET 10介绍 .NET 10 是 .NET 9 的后继版本&#xff0c;将作为长期支持维护 &#xff…

HTTP 黑科技

&#x1f9d1; 博主简介&#xff1a;CSDN博客专家&#xff0c;历代文学网&#xff08;PC端可以访问&#xff1a;https://literature.sinhy.com/#/literature?__c1000&#xff0c;移动端可微信小程序搜索“历代文学”&#xff09;总架构师&#xff0c;15年工作经验&#xff0c;…

C++20 模块:告别头文件,迎接现代化的模块系统

文章目录 引言一、C20模块简介1.1 传统头文件的局限性1.2 模块的出现 二、模块的基本概念2.1 模块声明2.2 模块接口单元2.3 模块实现单元 三、模块的优势3.1 编译时间大幅减少3.2 更好的依赖管理3.3 命名空间隔离 四、如何使用C20模块4.1 编译器支持4.2 示例项目4.3 编译和运行…

计算光学成像与光学计算概论

计算光学成像所涉及研究的内容非常广泛&#xff0c;虽然计算光学成像的研究内容是发散的&#xff0c;但目的都是一致的&#xff1a;如何让相机记录到客观实物更丰富的信息&#xff0c;延伸并扩展人眼的视觉感知。总的来说&#xff0c;计算光学成像现阶段已经取得了很多令人振奋…

安铂克科技 APPH 系列相位噪声分析仪:高性能测量的卓越之选

在当今的电子测量领域&#xff0c;对于信号源及各类设备的精确评估至关重要。安铂克科技的 APPH 系列相位噪声分析仪&#xff08;亦称作相噪仪、相位噪声测量仪、信号源分析仪&#xff09;&#xff0c;凭借其超凡的性能与全面的功能&#xff0c;成为众多工程师与科研人员的理想…

算法探秘:盛最多水的容器问题

目录 一、问题引入 二、示例剖析 三、暴力解法与困境 四、双指针法&#xff1a;优雅的解决方案 五、总结 一、问题引入 在算法的奇妙世界里&#xff0c;常常会遇到各种有趣又富有挑战性的问题&#xff0c;“盛最多水的容器”就是其中之一。想象一下&#xff0c;有一系…

QTday4

1:是进度条通过线程自己动起来 mythread.h #ifndef MYTHREAD_H #define MYTHREAD_H #include <QThread>class mythread : public QThread {Q_OBJECT public:mythread(QObject* parent nullptr); protected:virtual void run() override; private: signals:virtual voi…

PPT小黑第26套

对应大猫28 层次级别是错的&#xff0c;看着是十页&#xff0c;导入ppt之后四十多页 选中所有 红色蓝色黑色 文本选择标题&#xff1a;选择 -格式相似文本&#xff08;检查有没有漏选 漏选的话 按住ctrl 点下一个&#xff09; 要求新建幻灯片中不包含原素材中的任何格式&…

transformer架构解析{掩码,(自)注意力机制,多头(自)注意力机制}(含代码)-3

目录 前言 掩码张量 什么是掩码张量 掩码张量的作用 生成掩码张量实现 注意力机制 学习目标 注意力计算规则 注意力和自注意力 注意力机制 注意力机制计算规则的代码实现 多头注意力机制 学习目标 什么是多头注意力机制 多头注意力计算机制的作用 多头注意力机…

Spring编写单元测试的工具介绍:JUnit、Mockito、AssertJ

背景&#xff1a; 在Spring应用程序中&#xff0c;想要通过代码走查做好测试左移&#xff0c;单元测试是确保代码质量和功能正确性的关键。除了我们常用的TestNG外&#xff0c;本次介绍一下其他常见的单元测试工具: JUnit、Mockito、AssertJ&#xff0c;来提高我们做白盒测试的…

Kubermetes 部署mysql pod

步骤 1: 创建 PersistentVolume 和 PersistentVolumeClaim 首先为 MySQL 创建一个 PersistentVolume (PV) 和 PersistentVolumeClaim (PVC) 来确保数据的持久性。 mysql-pv.yaml&#xff1a; apiVersion: v1 kind: PersistentVolume metadata:name: mysql-pv-volume spec:cap…

论坛社区基础版【项目测试报告】

文章目录 一、项目背景二、项目功能用户注册/登录帖子列表页发布帖子个人中心 三、测试工具和环境四、测试计划非功能测试用例功能测试用例部分人工手动测试截图web自动化测试测试用例代码框架 配置内容代码文件&#xff08;Utils.py&#xff09;注册页面代码文件&#xff08;R…

物联网IoT系列之MQTT协议基础知识

文章目录 物联网IoT系列之MQTT协议基础知识物联网IoT是什么&#xff1f;什么是MQTT&#xff1f;为什么说MQTT是适用于物联网的协议&#xff1f;MQTT工作原理核心组件核心机制 MQTT工作流程1. 建立连接2. 发布和订阅3. 消息确认4. 断开连接 MQTT工作流程图MQTT在物联网中的应用 …

如何面向DeepSeek编程,打造游戏开发工具集,提升工作效率

最近我在思考&#xff1a; 如何基于DeepSeek&#xff0c;来提升工作效率&#xff0c;构建高效游戏开发工作流。 方向有两个: A: 基于DeepSeek私有代码框架&#xff0c;让它完成项目代码的续写; B: 基于DeepSeek来创作一些工具&#xff0c;使用工具来提升效率&#xff0c;如…

云原生机密计算:构建基于可信执行环境的数据安全堡垒

引言&#xff1a;数据计算的最后一道防线 蚂蚁集团金融级机密计算平台承载日均20亿次敏感交易&#xff0c;密钥泄露风险降低99.97%。微软Azure DCsv3系列虚拟机实现SGX全内存加密性能损耗<15%&#xff0c;Google Anthos Confidential将跨云数据传输成本压缩45%。Gartner预测…

通用文件模型

一、通用文件模型 通常一个完整的Linux系统有数千到数百万个文件组成&#xff0c;文件中存储了程序、数据和各种信息。层次化的目录结构用于对文件进行编排和分组。 1.ReiserFS(新型的文件系统) -->Reiser4 它通过一种与众不同的方式----完全平衡树来容纳数据&#xff0c;包…

产品管理过程-思维导图

产品管理过程 1. 市场调研 与用户交流与直接面对客户的一线同事如销售、客服、技术支持等交流市场研究报告分析竞争对手分析用户数据分析 2. 需求管理 需求来源管理 市场需求内部需求运营需求战略需求其它需求 需求版本管理 需求分配管理 需求跟踪管理 3. 产品规划 市…

EtherNet/IP转Modbus解析基于网关模块的罗克韦尔PLC与Modbus上位机协议转换通讯案例

在工业自动化控制系统中&#xff0c;常常会遇到不同品牌和通信协议的设备需要协同工作的情况。本案例中&#xff0c;客户现场采用了 AB PLC&#xff0c;但需要控制的变频器仅支持 Modbus 协议。为了实现 AB PLC 对变频器的有效控制与监控&#xff0c;引入了捷米特 JM-EIP-RTU 网…

【进程和线程】(面试高频考点)

【进程和线程】 前言 在计算机编程领域&#xff0c;并发编程是一项至关重要的技术&#xff0c;而进程和线程正是实现并发编程的核心概念。为了让大家更直观地理解并发编程的作用&#xff0c;我们先来看一个简单的生活例子。 想象一下&#xff0c;现在有一大份美味的饭菜&…

HTML 编辑器推荐与 VS Code 使用教程

在进行 HTML 编程时&#xff0c;选择一款合适的 HTML 编辑器能极大地提高开发效率。以下为大家推荐几款常用且功能强大的 HTML 编辑器&#xff0c;同时详细介绍如何使用 VS Code 创建和预览 HTML 文件。 一、HTML 编辑器推荐 VS Code&#xff1a;由微软开发&#xff0c;是一款…