Linux | 深入探究Linux进程控制:从fork函数到进程等待再到进程替换

news2024/9/20 20:22:56

目录

1、进程的创建:fork函数

2、父子进程的奇怪现象:为什么同一个地址有不同的值?——区分内存的虚拟地址和物理地址

代码:利用fork函数的返回值进行父子进程分流,执行不同的代码块

虚拟地址和物理地址:

fork调用和地址空间的关系:

3、进程的终止

进程终止的三种方式:return、exit 和 _exit

return

exit

_exit

注意:

进程退出码

4、进程等待:wait和waitpid

进程等待作用概述:

进程等待的方法:

wait 函数:

waitpid 函数:

进程退出的场景:

status

WIFEXITED(status)

WEXITSTATUS(status)

示例:

5、进程程序替换:exec函数族

函数声明:

系列函数的命名规则:

示例:


Linux操作系统以其强大的多任务处理能力和丰富的系统调用而著称。在Linux中,进程是执行中程序的实例,而进程控制是操作系统中一个至关重要的概念。本文将深入探讨Linux进程的创建、终止以及进程间的通信方式,并通过实现一个简单的shell程序来加深理解。

1、进程的创建:fork函数

在Linux中,fork函数是创建新进程的核心。当一个进程调用fork时,它会复制自己,生成一个几乎完全相同的副本,即子进程。这个子进程具有父进程的内存、文件描述符等资源的副本。fork函数的返回值在父进程中是子进程的PID,在子进程中则是0。

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

pid_t fork(void);

创建新的子进程通常有一下两种用法:

  1. 利用fork函数的返回值进行父子进程分流,执行不同的代码块。
  2. 进程替换,执行不同的程序。

fork() 函数的返回值有三种情况:

  1. 在父进程中:如果 fork() 成功,它将返回新创建的子进程的PID。这个值是一个正整数。
  2. 在子进程中:如果 fork() 成功,它将返回0。子进程认为自己是新创建的,并且它的PID是0。
  3. 在出错时:如果 fork() 调用失败,它将在父进程中返回-1,并设置全局变量 errno 以指示错误的原因。常见的错误原因包括但不限于:
    • EAGAIN:系统达到其进程数量的最大值,无法创建更多的进程。
    • ENOMEM:系统内存不足,无法分配足够的内存来创建新的进程。

示例:

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

int main() {
    pid_t pid = fork();  // 创建子进程

    if (pid < 0) {
        // fork失败
        fprintf(stderr, "Fork failed");
        return 1;
    } else if (pid == 0) {
        // 子进程
        printf("I am the child process, PID: %d\n", getpid());
    } else {
        // 父进程
        printf("I am the parent process, PID: %d, Child PID: %d\n", getpid(), pid);
    }

    return 0;
}

2ad484d3dc0a5f1c01c5429e2e417c86.png

2、父子进程的奇怪现象:为什么同一个地址有不同的值?——区分内存的虚拟地址和物理地址

代码:利用fork函数的返回值进行父子进程分流,执行不同的代码块

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
int main()
{   
    int x = 1000;
    pid_t id = fork();
    if(id < 0)
    {
        printf("fork() error\n");
        return -1;
    }
    else if(id == 0)
    {
        // child
        x = 10086; // 子进程修改x的值(其实就是修改对应内存啦~)
        printf("child: x = %d, &x->%p\n", x, &x);
    }
    else
    {
        // father 父进程没有就该x的值
        printf("father: x = %d, &x->%p\n", x, &x);
    }

    return 0;
}

运行结果:

d2b254cafeff531f8ea9f6ac65352250.png

虚拟地址和物理地址:

  1. 虚拟地址:每个进程都有自己的虚拟地址空间,这是操作系统为进程提供的抽象。虚拟地址空间中的地址可以通过内存管理单元(MMU)转换为物理地址。
  2. 物理地址:物理地址是实际存储在内存芯片上的地址。物理内存是有限的,而虚拟地址空间通常远大于物理内存。

解释:在子进程中,x 的值被修改为 10086。这个修改会让操作系统对子进程分配新的虚拟地址和物理地址的映射关系,(也就是新的页表~),最终只影响子进程的虚拟地址空间对应的新的物理内存区域,而虚拟地址不变(相同也不要紧)。也就是说,C语言中的地址其实是虚拟地址,不是真实的物理地址!!!

fork调用和地址空间的关系:

  • fork() 被调用时,子进程获得父进程的虚拟地址空间的副本。这意味着子进程有自己的虚拟地址到物理地址的映射,但是初始时这个映射与父进程相同。
  • 子进程对虚拟地址空间的写操作会导致写时拷贝(copy-on-write, COW)。如果子进程尝试修改其地址空间中的任何页面,操作系统会首先为该页面创建一个新的物理页面,然后将该页面的内容复制到新的物理页面,并将子进程的虚拟地址映射到这个新的物理页面。

90645dd13257a0aef821616c4f6d6dcd.png

Linux中的写时拷贝机制是一种优化内存使用的技术。在父子进程共享数据时,只有当数据被修改时,才会为修改它的进程创建数据的副本。这减少了不必要的内存复制,提高了效率。(原理就是在实际场景中,读数据频率远大于写数据,比如你看的博客数量一定大于你写不博客的数量~)

3、进程的终止

进程的终止可以是正常或异常的。正常终止可以通过从main函数返回、调用exit函数或_exit函数来实现。exit函数在终止前会执行一些清理工作,如关闭文件描述符、执行注册的退出处理函数等。而_exit函数则直接终止进程,不进行任何清理。

进程终止的三种方式:returnexit_exit

return

    • return 是一个C语言关键字,用于从函数返回到调用者。
    • 它通常用于返回一个值给调用函数,并且可以用于任何函数,包括 main 函数。
    • 当在 main 函数中使用 return 语句时,程序会正常终止,并且返回一个退出状态码给操作系统。
    • return 可以带一个整数值,这个值通常用于表示程序的退出状态,其中 0 通常表示成功,非零值表示错误或异常退出。

示例:

int main() {
    // ...
    return 0; // 正常退出,返回状态码0
}

exit

    • exit 是C标准库函数,定义在 <stdlib.h> 头文件中。
    • exit 用于立即终止程序的执行,并返回一个状态码给操作系统。
    • exit 调用会进行一些清理操作,比如关闭所有打开的文件描述符、刷新标准I/O缓冲区、调用注册的退出处理函数等。
    • exit 同样接受一个整数值作为参数,表示退出状态码。

示例:

#include <stdlib.h>

int main() {
    // ...
    exit(0); // 正常退出,返回状态码0
}

_exit

    • _exit 是一个原始的系统调用,通常定义在 <unistd.h> 头文件中。
    • _exit 用于立即终止程序的执行,并返回一个状态码给操作系统,但它不会执行任何清理操作。
    • exit 不同,_exit 不会刷新标准I/O缓冲区或调用任何退出处理函数,它直接终止进程。
    • 这使得 _exitexit 快,但只应在确定不需要进行任何清理工作时使用。

示例:

#include <unistd.h>

int main() {
    // ...
    _exit(0); // 立即退出,不进行任何清理工作
}

注意:

  • return 是C语言关键字,用于从函数返回,包括 main 函数。
  • exit 是C标准库函数,用于正常退出程序,并进行必要的清理工作。
  • _exit 是系统调用,用于立即退出程序,不进行任何清理工作,通常用于紧急情况或确定不需要清理的场景。
  • return n 等价于 exit(n)
  • C标准库中的exit 在实现上,调用系统 _exit 接口之后,还会执行刷新缓冲区数据等善后操作。我们也可以从中发现,C语言的缓冲区不是在系统内部的,而是C语言自身开辟管理的空间。(因为系统提供的_exit不刷新缓冲区)。

8bd8c314d8aa6537f6379e18042ced4e.png

int main()
{
 printf("this is exit()\n");
 exit(0);
}
运行结果:
[lhy@localhost linux]# ./a.out
[lhy@localhost linux]# this is exit()

int main()
{
 printf("this is _exit()\n");
 _exit(0);
}
运行结果:
[lhy@localhost linux]# ./a.out
[lhy@localhost linux]#
                      // 这里因为退出后缓冲区没被刷新 所以没有显示print内容

进程退出码

进程的退出码是一个重要的状态指示,它告诉父进程或操作系统进程是如何终止的(就是你return 或者 exit 后面带的值)。退出码可以通过在终端中使用$?来查看。

11215a7f85e1c8d08744d84c31a557c0.png

4、进程等待:wait和waitpid

为了防止僵尸进程的产生并回收子进程资源,同时子进程来获取其退出状态,了解子进程是否成功完成任务,以及任务执行的结果。父进程需要等待子进程的结束。waitwaitpid函数允许父进程等待子进程的终止,并获取其退出状态。

对僵尸进程没有概念的同学可以参考这篇博客~

Linux | Linux进程万字全解:内核原理、进程状态转换、优先级调度策略与环境变量-CSDN博客

进程等待作用概述:

  1. 避免僵尸进程:当子进程完成其任务并退出时,它会转变为僵尸进程,等待父进程回收其资源。如果父进程不执行等待操作,子进程的进程描述符和部分资源不会被释放,导致系统资源浪费。
  2. 资源回收:父进程通过等待子进程,可以回收子进程使用的资源,包括内存、文件描述符等,确保系统资源的有效利用。
  3. 获取子进程状态:父进程可以通过等待子进程来获取其退出状态,了解子进程是否成功完成任务,以及任务执行的结果。
  4. 异常处理:如果子进程因为错误或异常退出,父进程可以通过等待子进程来获取这些信息,并进行相应的异常处理。
  5. 同步执行:在某些情况下,父进程可能需要等待所有子进程完成其任务后才能继续执行,进程等待提供了一种同步机制。

进程等待的方法:

waitwaitpid 是两个在 Unix 和类 Unix 系统中用于父进程等待子进程状态的系统调用。它们允许父进程获取子进程的退出状态,并在子进程退出后回收其资源。

wait 函数:

  • 函数原型
#include <sys/wait.h>
pid_t wait(int *status);
  • 功能wait 函数挂起父进程的执行,直到有一个子进程退出。如果有多个子进程已经退出,wait 将唤醒并返回第一个退出的子进程的信息。
  • 参数status 是一个输出型参数,用指向整数的指针来接收子进程的退出状态。
  • 返回值:返回终止的子进程的 PID。如果出现错误,返回 -1 并设置 errno
  • 特点wait 函数只能等待任何单个子进程的退出,不能指定等待特定的子进程。

waitpid 函数:

  • 函数原型
#include <sys/wait.h>
pid_t waitpid(pid_t pid, int *status, int options);
  • 功能waitpid 函数允许父进程等待指定的子进程 pid 退出。与 wait 不同,waitpid 可以等待特定的子进程。当pid参数设置为-1是,等待任何子进程。
  • 返回值:返回终止的子进程的 PID。如果指定的子进程没有退出,且 options 包含 WNOHANG,则返回 0。如果出现错误,返回 -1 并设置 errno
  • 参数
    • pid:指定要等待的子进程的 PID。如果设置为 -1,则等待任何子进程。
    • status:与 wait 相同,用于接收子进程的退出状态。
    • options:指定等待操作的一些选项,常用的选项有 WNOHANGWUNTRACED,也可以设置为0表示阻塞等待进程退出。

options解释:

0 :如果设置此选项,跟wait函数效果相同,阻塞等待进程退出。

WNOHANG:

  • WNOHANG 选项使得 waitpid 调用变为非阻塞。如果没有任何子进程已经终止,waitpid 会立即返回而不是挂起调用进程的执行。这种模式下,如果子进程尚未结束,waitpid 返回0,而不是等待子进程结束 。
  • 例如,在服务器程序中,你可能希望在服务请求的同时检查子进程的状态。使用 WNOHANG 可以避免服务器因为等待子进程而停止处理其他请求 。

WUNTRACED:

  • WUNTRACED 选项允许 waitpid 报告已经停止的子进程,而不仅仅是已经终止的子进程。这通常用于调试目的,当子进程被其他进程(如调试器)暂停时,waitpid 可以报告这些信息 。
  • 这个选项对于常规应用程序来说使用较少,主要是在需要跟踪子进程状态的特定场景下使用 。

进程退出的场景:

1、 运行完毕,结果正确——没人关心

2、运行完毕,结果错误——看错误码

3、根本没运行完就崩了——错误码失效

注意:当进程非正常退出,退出码已经失去原有意义!!!

比如当进程空指针直接错误终止返回,此时退出码没有来得及修改,返回值为0,但显然程序已经不是正常退出了

status

status 是一个整数变量,用于存储由 waitwaitpid 函数返回的子进程状态信息。当 waitwaitpid 被调用时,如果子进程已经终止,这些函数会将子进程的退出信息存储在 status 变量中。status 的值可以表示多种子进程终止的情况,包括正常退出、被信号终止、停止执行等。

status内部的结构:

458615c283b2eb5c492300b6b7d08a3d.png

WIFEXITED(status)

WIFEXITED 是一个宏((status >> 8) & 0xFF),用于检查 status 变量是否表示子进程是因调用 exit()_exit() 函数正常退出的。如果子进程正常退出,则 WIFEXITED(status) 宏返回一个非零值(通常是1),表示子进程的退出状态可用;如果子进程不是正常退出的,则返回0。

WEXITSTATUS(status)

WEXITSTATUS 是一个宏(status & 0x7F),用于提取子进程的退出状态码。当 WIFEXITED(status) 返回非零值,表明子进程是正常退出的,此时可以使用 WEXITSTATUS(status) 宏来获取子进程的退出码。退出码是由子进程在退出时通过 exit() 函数的参数指定的,通常用于指示程序的退出原因或状态。

示例:

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

int main() {
    pid_t pid = fork(); // 创建子进程

    if (pid == -1) {
        perror("fork failed");
        exit(EXIT_FAILURE);
    } else if (pid == 0) {
        // 子进程
        exit(123); // 正常退出
    } else {
        // 父进程
        int status;
        pid_t terminated_pid = wait(&status); // 等待子进程结束

        if (WIFEXITED(status)) {
            printf("子进程退出,返回状态码:%d\n", WEXITSTATUS(status));
        } else {
            printf("子进程非正常退出\n");
        }
    }

    return 0;
}

4ccfc88f93ce1403f365f19a1352f487.png

在这个示例中,父进程使用 wait() 系统调用等待子进程结束,并获取子进程的退出状态。通过 WIFEXITED() 宏检查子进程是否正常退出,并使用 WEXITSTATUS() 宏获取子进程的退出状态码。

5、进程程序替换:exec函数族

exec函数族用于替换当前进程的映像为新的程序。这在shell中常用于执行用户输入的命令。进程替换函数族包括execlexeclpexecleexecvexecvpexecve等。

函数声明:

#include <unistd.h>

// 在当前进程映像中执行一个新的程序,path 是新程序的路径,arg 是主参数(通常是程序名)
// 后续参数是通过可变参数列表 (...) 传递的,以 NULL 结尾
int execl(const char *path, const char *arg, ...);

// 类似于 execl,但在系统环境变量 PATH 中搜索程序文件
int execlp(const char *file, const char *arg, ...);

// 类似于 execl,但允许传递环境指针 envp,envp 是环境变量数组,以 NULL 结尾
int execle(const char *path, const char *arg, ..., char *const envp[]);

// 在当前进程映像中执行一个新的程序,path 是新程序的路径
// argv 是指向参数列表的指针数组,参数列表以 NULL 结尾
int execv(const char *path, char *const argv[]);

// 类似于 execv,但在系统环境变量 PATH 中搜索程序文件
int execvp(const char *file, char *const argv[]);

系列函数的命名规则:

虽然函数杂乱,但是都是按照此规则命名的exec+数据容器(list列表或vector数组)+环境变量(路径或者自己维护的环境变量数组)

c5fd4a11d52ac2564522a3a2de65bb0b.png

#include <unistd.h>
int main()
{
 char *const argv[] = {"ps", "-ef", NULL};
 char *const envp[] = {"PATH=/bin:/usr/bin", "TERM=console", NULL};

 execl("/bin/ps", "ps", "-ef", NULL);
 
// 带p的,可以使用环境变量PATH,无需写全路径
 execlp("ps", "ps", "-ef", NULL);
 
// 带e的,需要自己组装环境变量
 execle("ps", "ps", "-ef", NULL, envp);

 execv("/bin/ps", argv);
 
// 带p的,可以使用环境变量PATH,无需写全路径
 execvp("ps", argv);
 
// 带e的,需要自己组装环境变量
 execve("/bin/ps", argv, envp);

 exit(0);
}

示例:

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

int main() {
    pid_t id = fork();
    if (id < 0) {
        // fork失败
        return -1;
    } else if (id == 0) {
        // 子进程
        // 执行 /bin/ps 程序并显示 -al 选项的结果
        execl("/bin/ps", "ps", "-al", NULL);
        // 如果execl成功执行,将不会到达这里
        perror("execl failed");
        exit(EXIT_FAILURE);
    } else {
        // 父进程
        int status = 0;
        // 等待子进程结束
        wait(&status);
        // 检查子进程是否正常退出,并打印退出码
        if (WIFEXITED(status)) {
            printf("exit_code: %d\n", WEXITSTATUS(status));
        } else {
            // 子进程非正常退出
            printf("exit_fail\n");
        }
    }

    return 0;
}

运行结果,发现子进程被替换为ps命令进行执行。其实bash的原理也不过如此~

b007a04e297c7ae7a6ac9314a921733e.png

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

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

相关文章

selenium学习记录

1、初识selenium 概述&#xff1a; Selenium是一个Web的自动化测试工具&#xff0c;最初是为网站自动化测试而开发的&#xff0c;类型像我们玩游戏用的按键精灵&#xff0c;可以按指定的命令自动操作&#xff0c;不同是Selenium 可以直接运行在浏览器上&#xff0c;它支持所有…

【java】RuoYiBootstrap多模块版本-登陆请求流程解析

登陆请求流程逻辑图 Created with Raphal 2.3.0 &#xff08;1&#xff09;登陆流程解析 &#xff08;2&#xff09;【接下来所有业务都受ShiroConfig配置所过滤】 模块&#xff1a;ruoyi-framework 位置&#xff1a;src/main/java 包名&#xff1a;com.ruoyi.framework.config…

【机器学习】CNN的数学基础

&#x1f308;个人主页: 鑫宝Code &#x1f525;热门专栏: 闲话杂谈&#xff5c; 炫酷HTML | JavaScript基础 ​&#x1f4ab;个人格言: "如无必要&#xff0c;勿增实体" 文章目录 CNN的数学基础1. 引言2. 卷积运算2.1 连续卷积2.2 离散卷积2.3 互相关 3. 激活函…

【html+css 绚丽Loading】 - 000007 虚空灵瞳

前言&#xff1a;哈喽&#xff0c;大家好&#xff0c;今天给大家分享htmlcss 绚丽Loading&#xff01;并提供具体代码帮助大家深入理解&#xff0c;彻底掌握&#xff01;创作不易&#xff0c;如果能帮助到大家或者给大家一些灵感和启发&#xff0c;欢迎收藏关注哦 &#x1f495…

一条短视频变现23万!不上班也能赚钱的路子

AI助力&#xff0c;让创意在短视频界翻涌成金。 这个项目不仅展示了AI技术在内容创作上的巨大潜力&#xff0c;更为那些希望在短视频平台上实现快速变现的创作者提供了一条可行之路。 何以破局&#xff0c;唯有行动。 我们相信每个人都有机会成为AI时代的弄潮儿。 01 项目…

SSM无人共享棋牌室的设计与实现---附源码99858

目 录 1 绪论 1.1 研究背景 1.2 研究意义 1.3国内外研究或应用现状&#xff1a; 1.4论文结构与章节安排 2 无人共享棋牌室系统分析 2.1 可行性分析 2.2 系统流程分析 2.2.1 数据增加流程 2.2.2 数据修改流程 2.2.3 数据删除流程 2.3 系统功能分析 2.3.1 功能性分析…

轻松上手!2024年图片转PDF工具操作指南

图片以其直观、生动的特点&#xff0c;成为传递信息的重要载体&#xff1b;而PDF文件则凭借其跨平台兼容性等特点在文档保存、传输及展示方面展现出巨大优势。因此&#xff0c;将图片转化为PDF格式的需求日益增长。那么&#xff0c;图片转为pdf怎么弄这次我们一起来探索。 1.F…

使用git时出现的问题总结

问题1 fatal: Unable to create ‘V:/Web/Vue3_admin/.git/index.lock’: File exists. 解决方法 删除 .git文件中的 index.lock 问题2 error: open("~$数据库表格.xlsx"): Permission denied error: unable to index file ~$数据库表格.xlsx 解决&#xff1a;要…

SpringBean的实例化,后置处理器以及生命周期

目录 一.Bean实例化的基本流程&#xff1a; Bean对象----->BeanDefinition信息对象 BeanDefintion存储到一个名为beanDefinitionMap中 对象存储在一个名为singletonObjects的Map中 Bean实例化的基本流程&#xff1a; 二.Spring的后处理器 Bean工厂后处理器- BeanFacto…

【C++题解】1137 - 纯粹素数

欢迎关注本专栏《C从零基础到信奥赛入门级&#xff08;CSP-J&#xff09;》 问题&#xff1a;1137 - 纯粹素数 类型&#xff1a;自定义函数 题目描述&#xff1a; 纯粹素数是这样定义的&#xff1a;一个素数&#xff0c;去掉最高位&#xff0c;剩下的数仍为素数&#xff0c;…

23D题分析

AM 分析方法&#xff1a;FFT&#xff0c;fc/fcfm/fc-fm调幅系数&#xff1a;ma Am/Ac&#xff0c;信号幅度 除 直流偏置调制方式&#xff1a;先给m(t)加Am直流偏置&#xff0c;再乘载波调制&#xff0c;如图&#xff1a; 公式&#xff1a; 5. 波形&#xff1a; 调幅系数&…

聚星文社和虹猫哪个好

聚星文社和虹猫是两个不同的公司&#xff0c;各有各的特点。下面是它们各自的优点&#xff1a; 聚星文社&#xff1a;Docshttps://docs.qq.com/doc/DRU1vcUZlanBKR2xy 聚星文社是一家传媒公司&#xff0c;专注于出版漫画、动画、小说等内容&#xff0c;拥有丰富的IP资源和创作…

Focal Loss 的详细解释

Focal Loss 是一种专为解决类别不平衡问题而设计的损失函数&#xff0c;最初由 Facebook AI 研究团队在 2017 年提出&#xff0c;特别用于物体检测任务&#xff08;如 RetinaNet 模型&#xff09;。在这些任务中&#xff0c;正负样本&#xff08;即目标对象和背景&#xff09;的…

mybatis druid postgresql statement超时原理原理

yaml设置超时 mybatis-plus:mapper-locations: classpath:/mapper/*.xml # MyBatis Mapper XML文件的位置type-aliases-package: com.company.mi.entity # 实体类所在的包configuration:default-statement-timeout: 10 configuration 设置超时 BaseStatementHandler设置超时 …

高校能耗监测

为了对校园能耗实行量化管理、实时监测&#xff0c;需要建立一个完善的监管体系校园节能监管体系。而节能监管体系的核心是能耗监测平台&#xff0c;本文介绍了一种基于智能网关的能耗监测系统的建设方法&#xff0c;并给出了系统的具体建设实施方法&#xff0c;具有一定的理论…

无法找到模块“vuex”的声明文件。“../node_modules/vuex/dist/vuex.mjs”隐式拥有 “any“ 类型。

写一个模拟的springbootvuw的demo的时候&#xff0c;需要用到vuex&#xff0c;结果按照示例&#xff0c;安装好&#xff0c; 行以下命令&#xff0c;安装Vuex &#xff0c;注&#xff1a;我的项目是vue2的项目&#xff0c;所以安装的是3.6.2版本的vuex npm install vuex3.6.2…

【MySQL进阶之路】数据类型

目录 概览 整型 bit类型 小数类型 FLOAT和DOUBLE 精度丢失问题 decimal 字符串类型 char varchar char和varchar 时间类型 enum和set 个人主页&#xff1a;东洛的克莱斯韦克-CSDN博客 【MySQL进阶之路】MySQL基础——从零认识MySQL-CSDN博客 概览 分类数据类型说…

如何使用dd命令制作银河麒麟系统镜像U盘启动盘?

如何使用dd命令制作银河麒麟系统镜像U盘启动盘&#xff1f; 1、引言2、准备工作1. 准备Linux系统2. 下载银河麒麟系统镜像3. 准备U盘 3、制作U盘启动盘1. 查看U盘设备路径2. 使用dd命令写入镜像3. 等待写入完成 4、验证与使用 &#x1f496;The Begin&#x1f496;点点关注&…

Windows内核学习之Demo1隐藏进程

内核层如下&#xff1a; 读写进程内存不太想写&#xff0c;以后再补吧 #include <ntifs.h>#define DEVICE_NAME L"\\Device\\MyDevice" #define SYMLINK_NAME L"\\DosDevices\\MyDevice" #define IOCTL_PROCESS_MEMORY CTL_CODE(FILE_DEVICE_UNKNO…

Maven 缺失jar手动安装

Maven 缺失jar手动安装 依赖报缺失&#xff0c;手动到nexus下载jar包 执行以下命令&#xff0c;安装。 mvn install:install-file -DgroupIdcom.xmal -DartifactIdesbhelper -Dversion2.0 -Dpackagingjar -DfileD:\lorepository\com\esbhelper-2.0.jarmvn install:install…