Linux编程:2、进程基础知识

一、进程基本概念

1、进程与程序的区别
  • 程序:静态的可执行文件(如电脑中的vs2022安装程序)。
  • 进程:程序的动态执行过程(如启动后的vs2022实例),是操作系统分配资源的单位(如 CPU 时间、内存)。
  • 特点:同一程序可启动多个进程(如多个 vs2022 窗口),进程关闭后程序仍存在。
2、进程的组成
  • 进程控制块(PCB):操作系统为每个进程创建的唯一标识,包含进程状态、资源信息等。
  • 程序段(代码):进程执行的代码逻辑。
  • 数据集(数据):进程操作的数据。

二、进程控制块(PCB)

1、核心字段
  • 进程号(PID):32 位无符号整数(Linux 最大为 32767),通过getpid()获取当前进程号。
  • 进程状态
    • R:可执行状态。
    • S:可中断睡眠。
    • D:不可中断睡眠。
    • T:暂停或跟踪状态。
    • Z:僵尸进程(已退出但未释放资源)。
    • X:即将销毁的进程。
  • 查看命令ps -eo stat,pid,user,cmd(显示状态、PID、用户、命令)。
2、其他字段
  • 优先级:决定 CPU 调度顺序。
  • CPU 现场信息:保存进程暂停时的 CPU 状态,以便恢复。
  • 资源清单:内存、I/O 设备等分配情况。
  • 队列指针:链接同一状态的进程(如就绪队列、等待队列)。

三、进程 PID 文件

1、存储位置:
  • 位于/var/run目录,文件名通常为进程名.pid,内容为单行的进程号。
  • 注意:需程序自行创建,系统不会自动生成。
2、作用:
  • 防止程序重复启动(通过文件锁机制实现)。
  • 示例代码:通过fcntl加锁判断进程是否已运行。
    #include <fcntl.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/file.h>
    #include <sys/stat.h>
    #include <sys/types.h>
    #include <unistd.h>// PID文件路径,用于存储当前运行实例的进程ID
    #define PID_FILE "/var/run/test.pid"/*** 检查程序是否已在运行,确保只有一个实例** 返回值:*   0 - 程序未运行,当前是第一个实例*  -1 - 程序已在运行,当前实例退出*/
    int checkAlone(void)
    {int  fd;       // 文件描述符char buf[16];  // 存储PID的缓冲区// 打开或创建PID文件,使用O_CREAT标志确保文件存在fd = open(PID_FILE, O_RDWR | O_CREAT, 0666);if (fd < 0) {perror("open pid failed");  // 打印错误信息exit(1);                    // 打开失败时终止程序}// 定义文件锁结构,准备加写锁struct flock fl;fl.l_type   = F_WRLCK;   // 写锁类型fl.l_start  = 0;         // 从文件开始位置fl.l_whence = SEEK_SET;  // 以文件起始为基准fl.l_len    = 0;         // 锁定整个文件// 尝试加非阻塞写锁// 返回值:0-成功,-1-失败(文件已被锁定)int ret = fcntl(fd, F_SETLK, &fl);if (ret < 0) {close(fd);             // 关闭文件描述符printf("Had run.\n");  // 提示已有实例在运行return -1;             // 返回错误码}// 将当前进程ID写入PID文件sprintf(buf, "%ld", (long)getpid());write(fd, buf, strlen(buf) + 1);printf("first running.\n");  // 提示首次运行return 0;                    // 返回成功
    }int main(void)
    {// 检查程序是否已在运行if (checkAlone() < 0) {return -1;  // 已有实例在运行,退出当前进程}// 主程序逻辑:循环执行任务while (1) {printf("working...\n");   // 输出工作状态sleep(1);                // 休眠1秒}return 0;
    }
 3、开启两个终端:

第一次运行程序(第一个终端):

第二次运行程序(第二个终端) :


四、进程的创建

1、fork () 函数
  • 功能:创建子进程,返回两次(父进程返回子进程 PID,子进程返回 0)。
  • 特点:子进程复制父进程的内存空间(不共享内存),继承打开的文件描述符等资源。
  • 示例1
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>int main()
    {int count = 0;  // 用于父子进程各自计数的变量printf("准备创建子进程...\n");// 创建子进程:fork调用会返回两次// 父进程返回子进程的PID(正值)// 子进程返回0// 返回负值表示创建失败pid_t pid = fork();// 错误处理:创建子进程失败if (pid < 0) {printf("创建子进程失败");exit(1);  // 终止程序并返回错误码1}// 子进程执行分支else if (pid == 0) {// 子进程中fork返回0// getpid()返回子进程自身的PIDprintf("我是子进程,pid=%d, 进程号=%d\n", pid, getpid());count++;  // 子进程的count加1}// 父进程执行分支else {// 父进程中fork返回子进程的PID// getpid()返回父进程自身的PIDprintf("我是父进程, pid=%d, 进程号=%d\n", pid, getpid());count++;  // 父进程的count加1}// 父子进程都会执行此语句// 通过判断pid值区分当前是哪个进程printf("我是%s, count=%d\n", pid == 0 ? "子进程" : "父进程", count);return 0;
    }

    说明1:
    由 fork 创建的新进程被称为子进程,原来的进程,称为“父进程”

    该函数被调用一次,但返回两次(在父进程中返回 1 次,子进程中返回 1 次)
    1)子进程的返回值是 0
    2)而父进程的返回值是子进程的 PID


    fork 执行完之后,子进程和父进程继续执行 fork 之后的指令。
    父进程和子进程几乎是等同的,它们具有相同的变量值(但变量内存并不共享),
    打开的文件也都相同,还有其他一些相同属性。
    如果父进程改变了变量的值,子进程将不会看到这个变化。
    实际上, 子进程是父进程的一个复制(拷贝),但它们并不共享内存。
    父进程改变了变量的值,子进程中对应的变量不会有任何影响。

  • 示例2:

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>int main()
    {int count = 0;  // 父子进程各自的计数器printf("准备创建子进程...\n");pid_t pid;// 循环两次创建子进程,每次fork会产生父子两个分支for (int i = 0; i < 2; i++) {pid = fork();  // 关键系统调用:创建新进程if (pid < 0) {perror("fork失败");  // 输出系统错误信息exit(1);             // 异常退出}else if (pid == 0) {// 子进程分支:pid为0,getpid()返回子进程IDprintf("[新的子进程]我是子进程,pid=%d, 进程号=%d\n", pid,getpid());count++;  // 子进程计数器加1}else {// 父进程分支:pid为子进程ID,getpid()返回父进程IDprintf("我是父进程, pid=%d, 进程号=%d\n", pid, getpid());count++;  // 父进程计数器加1}}// 父子进程最终都会执行此语句// 通过最后一次fork的返回值判断当前是父进程还是子进程printf("我是%s, count=%d\n", pid == 0 ? "子进程" : "父进程", count);return 0;
    }



    for 循环了 2 次,实际上创建了 3 个子进程,而不是两个。

2、exec 系列函数
  • 功能:用指定程序替换当前进程(成功后原进程代码不再执行)。
  • 接口差异
    • l:参数以列表形式传递(如execl)。
    • p:从 PATH 环境变量查找程序(如execlp)。
    • v:参数通过指针数组传递(如execv)。
    • e:传递自定义环境变量(如execle)。
  • 示例
    无参的:
     
    #include <cstdio>
    #include <unistd.h>int main(int argc, char* argv[])
    {// 使用execl函数执行外部程序,替换当前进程映像// 参数1: 要执行的程序路径// 参数2开始: 传递给程序的命令行参数,必须以NULL结尾execl("/bin/pwd",         // 指定要执行的程序路径(绝对路径)"pwd",              // 命令行参数列表的第一个参数,通常是程序名(可自定义)NULL);              // 参数列表结束标记,必须为NULL// 如果execl调用成功,当前进程会被完全替换,不会执行到这里// 如果执行到这里,说明execl调用失败perror("execl failed");  // 打印系统错误信息return 1;                // 返回错误退出码
    }



    带参的:

    #include <unistd.h>
    int main(int argc, char* argv[])
    {// 相当于执行: ls -l /tmpexecl("/bin/ls", "ls", "-l", "/tmp", NULL);return 0;
    }

3、fork 与 exec 结合

  • 场景:父进程创建子进程后,子进程执行新程序(如 Shell 命令解析)。
  • 示例逻辑
    pid_t pid = fork();
    if (pid == 0) { execv("/path/to/program", argv); } // 子进程执行新程序

 

五、进程的分类

1、前台进程
  • 定义:需与用户交互的进程(如终端运行的程序),默认启动即为前台。
  • 查看命令ps -e | grep 进程名
2、后台进程
  • 定义:无需交互,在后台运行(如服务器程序)。
  • 启动方式:命令后加&(如./a.out &)。
  • 终止命令killall 进程名
3、守护进程
  • 定义:特殊后台进程,独立于终端(如sshdhttpd),用于长期运行任务。
  • 特点
    • 不依附终端,终端关闭后仍运行。
    • 父进程通常为systemd(PID 1)。
  • 创建步骤
    1. fork后退出父进程,子进程成为孤儿进程。
    2. setsid创建新会话,脱离原终端。
    3. chdir("/")切换工作目录至根目录。
    4. umask(0)清除文件权限掩码。
    5. 关闭默认文件描述符(0、1、2)。
  • 示例代码:通过信号处理实现日志写入的守护进程。
  • 查看命令ps axj(显示 PPID、会话信息等)。

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

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

相关文章

React Router 中 navigate 后浏览器返回按钮不起作用的问题记录

React Router 中 navigate 后浏览器返回按钮不起作用的问题记录 在使用 React Router&#xff08;v6&#xff09;开发项目时&#xff0c;我遇到了一个让人困惑的问题&#xff1a; 当我从 /article 页面使用 navigate("/article/next") 进行跳转后&#xff0c;点击浏…

[面试精选] 0094. 二叉树的中序遍历

文章目录 1. 题目链接2. 题目描述3. 题目示例4. 解题思路5. 题解代码6. 复杂度分析 1. 题目链接 94. 二叉树的中序遍历 - 力扣&#xff08;LeetCode&#xff09; 2. 题目描述 给定一个二叉树的根节点 root &#xff0c;返回 它的 中序 遍历 。 3. 题目示例 示例 1 : 输入&…

Addressable-配置相关

1、Profile 概述窗口配置 主要用于配置Addressable打包&#xff08;构建&#xff09;加载AB包时使用的一些变量,这些变量定义了 在哪里保存打包&#xff08;构建&#xff09;的AB包运行时在哪里加载AB包 可以添加自定义变量&#xff0c;以便在打包加载时使用,之后在设置 组中…

aws(学习笔记第四十三课) s3_sns_sqs_lambda_chain

文章目录 aws(学习笔记第四十三课) s3_sns_sqs_lambda_chain学习内容&#xff1a;1. 整体架构1.1 代码链接1.2 整体架构1.3 测试代码需要的修改1.3.1 unit test代码中引入stack的修改1.3.2 test_outputs_created代码中把错误的去掉 2. 代码解析2.1 生成dead_letter_queue死信队…

Python训练营打卡Day43

kaggle找到一个图像数据集&#xff0c;用cnn网络进行训练并且用grad-cam做可视化 进阶&#xff1a;并拆分成多个文件 config.py import os# 基础配置类 class Config:def __init__(self):# Kaggle配置self.kaggle_username "" # Kaggle用户名self.kaggle_key &quo…

hive 3集成Iceberg 1.7中的Java版本问题

hive 3.1.3 集成iceberg 1.7.2创建Iceberg表报错如下&#xff1a; Exception in thread "main" java.lang.UnsupportedClassVersionError: org/apache/iceberg/mr/hive/HiveIcebergStorageHandler has been compiled by a more recent version of the Java Runtime …

文本切块技术(Splitter)

为什么要分块&#xff1f; 将长文本分解成适当大小的片段&#xff0c;以便于嵌入、索引和存储&#xff0c;并提高检索的精确度。 用ChunkViz工具可视化分块 在线使用 ChunkViz github https://github.com/gkamradt/ChunkViz 如何确定大模型所能接受的最长上下文 可以从…

C++:用 libcurl 发送一封带有附件的邮件

编写mingw C 程序&#xff0c;用 libcurl 发送一封带有附件的邮件 下面是一个使用 MinGW 编译的 C 程序&#xff0c;使用 libcurl 发送带附件的邮件。这个程序完全通过代码实现 SMTP 邮件发送&#xff0c;不依赖外部邮件客户端&#xff1a; // send_email.cpp #include <i…

tensorflow image_dataset_from_directory 训练数据集构建

以数据集 https://www.kaggle.com/datasets/vipoooool/new-plant-diseases-dataset 为例 目录结构 训练图像数据集要求&#xff1a; 主目录下包含多个子目录&#xff0c;每个子目录代表一个类别。每个子目录中存储属于该类别的图像文件。 例如 main_directory/ ...cat/ ...…

遨游Spring AI:第一盘菜Hello World

Spring AI的正式版已经发布了&#xff0c;很显然&#xff0c;接下来我们要做的事情就是写一个Hello World。 总体思路就是在本地搭建一个简单的大模型&#xff0c;然后编写Spring AI代码与模型进行交互。 分五步&#xff1a; 1. 安装Ollama&#xff1b; 2. 安装DeepSeek&…

华为云Flexus+DeepSeek征文|基于华为云Flexus X和DeepSeek-R1打造个人知识库问答系统

目录 前言 1 快速部署&#xff1a;一键搭建Dify平台 1.1 部署流程详解 1.2 初始配置与登录 2 构建专属知识库 2.1 进入知识库模块并创建新库 2.2 选择数据源导入内容 2.3 上传并识别多种文档格式 2.4 文本处理与索引构建 2.5 保存并完成知识库创建 3接入ModelArts S…

Java优化:双重for循环

在工作中&#xff0c;经常性的会出现在两张表中查找相同ID的数据&#xff0c;许多开发者会使用两层for循环嵌套&#xff0c;虽然实现功能没有问题&#xff0c;但是效率极低&#xff0c;一下是一个简单的优化过程&#xff0c;代码耗时凑从26856ms优化到了748ms。 功能场景 有两…

Prompt Tuning:生成的模型文件有什么构成

一、为什么Prompt Tuning会生成模型文件? 1. Prompt Tuning的本质:优化可训练的「提示参数」 核心逻辑:Prompt Tuning(提示调优)是一种轻量级的微调技术,仅优化模型输入层的提示向量(Prompt Embedding)或少量额外参数,而非更新整个预训练模型的权重。生成模型文件的原…

ARM SMMUv3简介(一)

1.概述 SMMU&#xff08;System Memory Management Unit&#xff0c;系统内存管理单元&#xff09;是ARM架构中用于管理设备访问系统内存的硬件模块。SMMU和MMU的功能类似&#xff0c;都是将虚拟地址转换成物理地址&#xff0c;不同的是MMU转换的虚拟地址来自CPU&#xff0c;S…

在 Windows 系统上运行 Docker 容器中的 Ubuntu 镜像并显示 GUI

在 Windows 上安装一个 X Server&#xff08;如 VcXsrv 或 X410&#xff09;&#xff0c;Ubuntu 容器通过网络将图形界面转发到 Windows。 步骤&#xff1a; 安装 X Server&#xff1a; 推荐使用VcXsrv&#xff0c;免费开源。 安装后运行 XLaunch&#xff0c;选择&#xff1…

Vue3学习(4)- computed的使用

1. 简述与使用 作用&#xff1a;computed 用于基于响应式数据派生出新值&#xff0c;其值会自动缓存并在依赖变化时更新。 ​缓存机制​&#xff1a;依赖未变化时直接返回缓存值&#xff0c;避免重复计算&#xff08;通过 _dirty 标志位实现&#xff09;。​响应式更新​&…

【HarmonyOS 5】出行导航开发实践介绍以及详细案例

以下是 ‌HarmonyOS 5‌ 出行导航的核心能力详解&#xff08;无代码版&#xff09;&#xff0c;聚焦智能交互、多端协同与场景化创新&#xff1a; 一、交互革新&#xff1a;从被动响应到主动服务 ‌意图驱动导航‌ ‌自然语义理解‌&#xff1a;用户通过语音指令&#xff08;如…

csrf攻击学习

原理 csrf又称跨站伪造请求攻击&#xff0c;现代网站利用Cookie、Session 或 Token 等机制识别用户身份&#xff0c;一旦用户访问某个网站&#xff0c;浏览器在之后请求会自动带上这些信息来识别用户身份。用户在网站进行请求或者操作时服务器会给出对应的内容&#xff0c;比如…

深入剖析MySQL锁机制,多事务并发场景锁竞争

一、隐藏字段对 InnoDB 的行锁&#xff08;Record Lock&#xff09;与间隙锁&#xff08;Gap Lock&#xff09;的影响 1. 隐藏字段与锁的三大核心影响 类型影响维度描述DB_TRX_IDMVCC 可见性控制决定是否读取当前版本&#xff0c;或在加锁时避开不可见版本&#xff08;影响加锁…

以SMMUv2为例,使用Trace32可视化操作SMMU的常用命令详解

Trace32支持一系列的SMMU命令&#xff0c;可以帮助用户更好地配置、查看和分析SMMU。换句话说&#xff0c;就是让SMMU的配置变得可视化。 在添加SMMU实例之前&#xff0c;需要选择一个CPU来激活该SMMU实例的相关命令。Trace32让SMMU的配置可视化的本质是&#xff0c;操纵CPU读取…