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、守护进程
- 定义:特殊后台进程,独立于终端(如
sshd
、httpd
),用于长期运行任务。 - 特点:
- 不依附终端,终端关闭后仍运行。
- 父进程通常为
systemd
(PID 1)。
- 创建步骤:
fork
后退出父进程,子进程成为孤儿进程。setsid
创建新会话,脱离原终端。chdir("/")
切换工作目录至根目录。umask(0)
清除文件权限掩码。- 关闭默认文件描述符(0、1、2)。
- 示例代码:通过信号处理实现日志写入的守护进程。
- 查看命令:
ps axj
(显示 PPID、会话信息等)。
相关文章:

Linux编程:2、进程基础知识
一、进程基本概念 1、进程与程序的区别 程序:静态的可执行文件(如电脑中的vs2022安装程序)。进程:程序的动态执行过程(如启动后的vs2022实例),是操作系统分配资源的单位(如 CPU 时…...
时序数据库IoTDB与EdgeX Foundry集成适配服务介绍
一、背景介绍 EdgeX Foundry:由Linux基金会运维的开放源码边缘计算软件框架,自2017年开源后广泛应用于全球各行业场景。VMware自2018年起在中国社区推广EdgeX技术,拓展生态,并持续贡献代码。IoTDB:由Apache基…...
Android第十二次面试-多线程和字符串算法总结
多线程的创建与常见使用方法 一、多线程创建方式 1. 继承Thread类 class MyThread extends Thread {Overridepublic void run() {// 线程执行逻辑System.out.println(Thread.currentThread().getName() " is running");} }// 使用 MyThread thread new …...
ES6——数组扩展之Set数组
在ES6(ECMAScript 2015)中,JavaScript的Set对象提供了一种存储任何值唯一性的方式,类似于数组但又不需要索引访问。这对于需要确保元素唯一性的场景非常有用。Set对象本身并不直接提供数组那样的方法来操作数据(例如ma…...

Cursor Rules 使用
前言 最近在使用 Cursor 进行编程辅助时,发现 AI 生成的代码风格和当前的代码风格大相径庭。而且有时它会输出很奇怪的代码,总是不符合预期。 遂引出本篇,介绍一下 Rules ,它就可以做一些规范约束之类的事情。 什么是 Cursor R…...

服务器数据恢复—服务器raid5阵列崩溃如何恢复数据?
服务器数据恢复环境&故障: 某品牌型号为X3850服务器上有一组由14块数据盘和1块热备盘组建的raid5磁盘阵列。 服务器在正常使用过程中突然崩溃,管理员查看raid5阵列故障情况的时发现磁盘阵列中有2块硬盘掉线,但是热备盘没有启用。 服务器数…...

Go语言堆内存管理
Go堆内存管理 1. Go内存模型层级结构 Golang内存管理模型与TCMalloc的设计极其相似。基本轮廓和概念也几乎相同,只是一些规则和流程存在差异。 2. Go内存管理的基本概念 Go内存管理的许多概念在TCMalloc中已经有了,含义是相同的,只是名字有…...

【DAY41】简单CNN
内容来自浙大疏锦行python打卡训练营 浙大疏锦行 知识点: 数据增强卷积神经网络定义的写法batch归一化:调整一个批次的分布,常用与图像数据特征图:只有卷积操作输出的才叫特征图调度器:直接修改基础学习率 卷积操作常…...
Rust 学习笔记:使用自定义命令扩展 Cargo
Rust 学习笔记:使用自定义命令扩展 Cargo Rust 学习笔记:使用自定义命令扩展 Cargo Rust 学习笔记:使用自定义命令扩展 Cargo Cargo 支持通过 $PATH 中的 cargo-something 形式的二进制文件拓展子命令,而无需修改 Cargo 本身。 …...
LeetCode 08.06 面试题 汉诺塔 (Java)
经典递归解决汉诺塔问题:清晰的三步移动策略 问题描述 在汉诺塔问题中,有 3 根柱子和 N 个大小不同的盘子,盘子初始按升序堆叠在第一根柱子上(最小的在顶部)。目标是将所有盘子移动到第三根柱子上,并满足…...

使用MinIO搭建自己的分布式文件存储
目录 引言: 一.什么是 MinIO ? 二.MinIO 的安装与部署: 三.Spring Cloud 集成 MinIO: 1.前提准备: (1)安装依赖: (2)配置MinIO连接: &…...
单元测试与QTestLib框架使用
一.单元测试的意义 在软件开发中,单元测试是指对软件中最小可测试单元(通常是函数、类的方法)进行隔离的、可重复的验证。进行单元测试具有以下重要意义: 1.提升代码质量与可靠性: 早期错误检测: 在开发…...
java面试场景题:QPS 短链系统怎么设计
以下是对文章的润色版本: 这道场景设计题,初看似乎业务简单,实则覆盖的知识点极为丰富: 高并发与高性能分布式 ID 生成机制;Redis Bloom Filter——高并发、低内存损耗的过滤组件知识;分库、分表海量数据存…...
java面试场景提题:
以下是润色后的文章,结构更清晰,语言更流畅,同时保留了技术细节: 应对百倍QPS增长的系统设计策略 整体架构设计思路 面对突发性百倍QPS增长,系统设计需从硬件、架构、代码、数据四个维度协同优化: 硬件层…...

K7 系列各种PCIE IP核的对比
上面三个IP 有什么区别,什么时候用呢? 7 series Integrated Block for PCIE AXI Memory Mapped to PCI Express DMA subsystem for PCI Express 特点 这是 Kintex-7 内置的 硬核 PCIe 模块。部分事务层也集成在里面,使用标准的PCIE 基本没…...

natapp 内网穿透失败
连不上网络错误调试排查详解 - NATAPP-内网穿透 基于ngrok的国内高速内网映射工具 如何将DNS服务器修改为114.114.114.114_百度知道 连不上/错误信息等问题解决汇总 - NATAPP-内网穿透 基于ngrok的国内高速内网映射工具 nslookup auth.natapp.cnping auth.natapp.cn...

深入解析CI/CD开发流程
引言:主播最近实习的时候发现部门里面使用的是CI/CD这样的集成开发部署,但是自己不是太了解什么意思,所以就自己查了一下ci/cd相关的资料,整理分享了一下 一、CI/CD CI/CD是持续集成和持续交付部署的缩写,旨在简化并…...

Docke启动Ktransformers部署Qwen3MOE模型实战与性能测试
docker运行Ktransformers部署Qwen3MOE模型实战及 性能测试 最开始拉取ktransformers:v0.3.1-AVX512版本,发现无论如何都启动不了大模型,后来发现是cpu不支持avx512指令集。 由于本地cpu不支持amx指令集,因此下载avx2版本镜像: …...

应用分享 | 精准生成和时序控制!AWG在确定性三量子比特纠缠光子源中的应用
在量子技术飞速发展的今天,实现高效稳定的量子态操控是推动量子计算、量子通信等领域迈向实用化的关键。任意波形发生器(AWG)作为精准信号控制的核心设备,在量子实验中发挥着不可或缺的作用。丹麦哥本哈根大学的研究团队基于单个量…...

相机--相机标定实操
教程 camera_calibration移动画面示例 usb_cam使用介绍和下载 标定流程 单目相机标定 我使用的是USB相机,所以直接使用ros的usb_cam功能包驱动相机闭关获取实时图像,然后用ros的camera_calibration标定相机。 1,下载usb_cam和camera_calibration: …...
深入理解汇编语言中的顺序与分支结构
本文将结合Visual Studio环境配置、顺序结构编程和分支结构实现,全面解析汇编语言中的核心编程概念。通过实际案例演示无符号/有符号数处理、分段函数实现和逻辑表达式短路计算等关键技术。 一、汇编环境配置回顾(Win32MASM) 在Visual Studi…...

DAY43 复习日
浙大疏锦行-CSDN博客 kaggle找到一个图像数据集,用cnn网络进行训练并且用grad-cam做可视化 进阶:把项目拆分成多个文件 src/config.py: 用于存放项目配置,例如文件路径、学习率、批次大小等。 # src/config.py# Paths DATA_DIR "data…...
【仿生机器人】仿生机器人智能架构:从感知到个性的完整设计
仿生机器人智能架构:从感知到个性的完整设计 仿生机器人不仅需要模拟人类的外表,更需要具备类人的认知、情感和个性特征。本研究提出了一个综合性的软件架构,实现了从环境感知到情感生成、从实时交互到人格塑造的完整智能系统。该架构突破了…...
【业务框架】3C-相机-Cinemachine
概述 插件,做相机需求,等于相机老师傅多年经验总结的工具 Feature Transform:略Control Camera:控制相机参数Noise:增加随机性Blend:CameraBrain的混合列表指定一个虚拟相机到另一个相机的过渡ÿ…...

【Auto.js例程】华为备忘录导出到其他手机
目录 问题描述方法步骤1.安装下载Visual Studio Code2.安装扩展3.找到Auto.js插件,并安装插件4.启动服务器5.连接手机6.撰写脚本并运行7.本文实现功能的代码8.启动手机上的换机软件 问题描述 问题背景:华为手机换成一加手机,华为备忘录无法批…...

单片机的低功耗模式
什么是低功耗? STM32的低功耗(low power mode)特性是其嵌入式处理器系列的一个重要优势,特别适用于需要长时间运行且功耗敏感的应用场景,如便携式设备、物联网设备、智能家居系统等。 在很多应用场合中都对电子设备的…...

架构师级考验!飞算 JavaAI 炫技赛:AI 辅助编程解决老项目难题
当十年前 Hibernate 框架的 N1 查询隐患在深夜持续困扰排查,当 SpringMVC 控制器中错综复杂的业务逻辑在跨语言迁移时令人抓狂,企业数字化进程中的百万行老系统,已然成为暗藏危机的 “技术债冰山”。而此刻,飞算科技全新发布的 Ja…...

手机端抓包大麦网抢票协议:实现自动抢票与支付
🚀 手机端抓包大麦网抢票协议:实现自动抢票与支付 🚀 🔥 你是否还在为抢不到热门演出票而烦恼?本文将教你如何通过抓包技术获取大麦网抢票协议,并编写脚本实现自动化抢票与支付!🔥 …...
使用阿里云百炼embeddings+langchain+Milvus实现简单RAG
使用阿里云百炼embeddingslangchainMilvus实现简单RAG 注意测试时,替换其中的key、文档等 import os from langchain_community.embeddings import DashScopeEmbeddings from langchain_community.vectorstores import Milvus from langchain_text_splitters impor…...
C#合并CAN ASC文件:实现与优化
C#合并CAN ASC文件:实现与优化 在汽车电子和工业控制领域,CAN(Controller Area Network)总线是一种广泛使用的通信协议。CAN ASC(American Standard Code)文件则是记录CAN总线通信数据的标准格式ÿ…...