操作系统进程管理实战:C语言实现fork、调度算法与信号量同步
简介操作系统进程管理实验的C语言实现资源面向高校操作系统课程学生及需要完成课程设计的开发者覆盖进程创建、撤销、同步、通信、调度及死锁处理等核心实验内容。压缩包为RAR格式共9个文件包含源码文件、头文件、编译生成的目标文件、可直接运行的程序以及工程配置文件整体仅19KB便于分发和快速部署。已有4169人学习浏览验证了其实用价值。资源通过fork、exec、wait等系统调用演示进程生命周期管理并涉及信号量、管道、消息队列等同步通信手段以及先来先服务、短进程优先、时间片轮转等调度算法的实现思路代码可直接运行观察效果也可二次修改以适配不同实验要求有助于从代码层面理解操作系统进程管理机制适合实验报告撰写与答辩准备。1. 操作系统进程管理实验把黑匣子拆成可复现的 C 代码操作系统这门课里进程管理是最容易让人挂科的章节之一。课本上 fork() 创建进程、FCFS 和 SPF 调度、信号量 PV 操作概念都配了流程图但真要自己写代码跑一遍很多人第一反应是无从下手。这份 ProcessControl 实验资源把进程控制块、就绪队列和三种调度算法用 C 语言完整落地压缩包里是 Code::Blocks 工程文件、头文件加 main.c 入口配置好编译器就能编译运行。适合正在上操作系统实验课、被进程调度报告逼到墙角的本科生也想用代码验证课本结论的自学者还有准备面试前快速过一遍进程生命周期和调度实现的求职者。看完这篇你能搞懂每个文件的作用、调度参数怎么设、以及最容易翻车的地方。2. 拆包 ProcessControl文件清单、工程结构与编译环境三件事2.1 压缩包里每个文件干什么.cbp 不是凑数解压 ProcessControl.rar 后看到的文件分三类工程配置、源码、编译产物。先给一张清单再逐个说明用途。文件/目录类型作用ProcessControl.cbp工程文件Code::Blocks 项目描述XML 格式记录源文件列表、编译选项、输出路径ProcessControl.h头文件PCB 结构体、状态常量、函数声明ProcessControl.c核心实现进程创建、状态迁移、调度算法等主要逻辑main.c入口文件初始化进程数据、调用调度函数、打印实验结果ProcessControl.depend自动生成头文件依赖关系IDE 维护可忽略ProcessControl.layout自动生成窗口布局删掉不影响编译obj/Debug中间产物.o 目标文件bin/Debug输出目录最终可执行文件所在位置.cbp 文件值得多说一句。它本质上是 XML里面记录着编译器类型、Debug/Release 配置、源文件路径和输出目录。你如果换了 IDE 重新建工程只要把 main.c 和 ProcessControl.c 两个源文件加进去头文件指对路径编译选项选 C99 或 C11效果和原来一模一样。第一次打开工程的同学建议用文本编辑器看一眼 .cbp 里的 XMLsource 标签下明明白白列着源文件option 标签里写着编译参数看懂这几十行以后任何 Code::Blocks 工程出问题你都能自己排查不用重装 IDE。.depend 和 .layout 是自动生成的辅助文件提交作业时可以不打包不影响任何功能。obj 和 bin 是构建产物bin/Debug 里的可执行文件就是编译后的程序分发源码时把这两个目录清掉再压缩体积小很多也避免别人拿到的是你本机的旧产物。2.2 ProcessControl.h 的数据结构PCB 怎么建模整个实验的地基是进程控制块PCB。课本上说 PCB 要记录状态、程序计数器、寄存器、内存边界但实验模拟到寄存器级别毫无必要通常只保留调度和状态迁移需要的字段。我一般这样定义#define MAX_PROC 16 #define READY 0 #define RUNNING 1 #define BLOCKED 2 #define FINISHED 3 typedef struct pcb { int pid; char name[16]; int arrive_time; /* 到达时间, 单位可以是秒或时间片 */ int need_time; /* 需要的总 CPU 时间 */ int remain_time; /* 剩余时间, 轮转调度递减 */ int priority; /* 优先级, 数字小优先 */ int state; /* READY / RUNNING / BLOCKED / FINISHED */ struct pcb *next; /* 就绪队列链表指针 */ } PCB;字段从前往后依次是进程号、名字、到达时间、需要的 CPU 时间、剩余时间、优先级、状态、链表指针。state 用宏常量表示比直接写 0/1/2/3 可读性好得多也不容易在状态判断里写错数字。next 指针是把 PCB 串成队列的关键这里用的就是 C 语言最经典的链表操作——插入、删除、遍历三个动作。你要是能把链表的头插、尾插和「删除中间节点要改前驱的 next」写熟调度队列基本不会出问题。这块用到的指针操作跟翁恺的 C 语言课里讲链表那几节是一模一样的套路基础不牢的先去补链表再动调度算法。这里有个容易混的点remain_time 和 need_time 是两个字段不是同一个。FCFS 和 SPF 只需要 need_time 来排序和计算完成时间时间片轮转每次执行完要递减 remain_time直到归零才置 FINISHED。把两个字段并成一个的同学轮转调度跑到一半就会发现进程「越跑越短」然后整个队列乱掉。定义结构体时把注释写全能省后面两小时的排错时间。2.3 编译环境Code::Blocks 与 Linux 的取舍这份资源用 Code::Blocks 建工程在国内高校实验环境里是最低摩擦的方案。装好 Code::Blocks自带 MinGW之后直接双击 .cbp点 Build 就能编译不需要额外配置。如果你习惯 VSCode配好 C/C 插件、把编译器路径指对新建空项目把三个源文件加进去同样能跑vscode 配置 c 语言环境那套流程在这里完全适用。Code::Blocks 左下角有 Debug 和 Release 两个编译目标做实验用 Debug 就行它带调试信息、编译优化默认关闭跑出来的结果和源码逻辑一一对应Release 开了优化后代码执行顺序可能和你写的不完全一致调试时只会添乱。但有一个必须先说清的边界实验中如果涉及 fork()、exec()、wait() 这类系统调用它们是 POSIX 接口Windows 的 MinGW 不提供。常见处理办法是把实验拆成两个层面看——调度模拟部分纯粹的数据结构加算法在 Windows 下随意编译真实的进程创建、进程间通信要在 linux 操作系统环境里跑WSL 或虚拟机都行。我在 linux 上习惯直接命令行编译gcc -Wall -g main.c ProcessControl.c -o process_control ./process_control-Wall 把警告全亮出来-g 保留调试信息给 gdb 用。很多同学拿着 .cbp 在 Windows 下一编译报 undefined reference to fork就以为资源是坏的其实只是跑错了环境。先确认代码里是否真的调用了 fork再用对应的环境编译问题立刻消失。main.c 的典型流程是先初始化一批 PCB 实例填好到达时间和服务时间再依次调用 FCFS、SPF、RR 三个调度函数最后打印每个进程的开始时间、完成时间并计算平均等待时间和平均周转时间。代码里如果看到 create_process() 这类函数它做的事就是把一个结构体实例挂到就绪队列尾部并不是真的调用操作系统 API 创建进程。搞清楚「模拟」和「真实调用」的界限读这份资源就不会被绕晕。3. fork/exec/wait 三件套进程生命周期在 Linux 下的 C 落地3.1 fork()返回值是三岔路口真实进程的创建靠 fork()。它的行为可以用一句话概括调用一次返回两次。父进程收到子进程的 pid子进程收到 0出错时返回 -1。这个返回值就是代码分流的开关。#include stdio.h #include unistd.h #include sys/wait.h int main(void) { pid_t pid fork(); if (pid 0) { perror(fork failed); return 1; } else if (pid 0) { /* 子进程从这里开始独立执行 */ printf(child: pid%d, my parent%d\n, getpid(), getppid()); } else { /* 父进程分支 */ printf(parent: pid%d, created child%d\n, getpid(), pid); } return 0; }fork 通过复制父进程的内存映像创建子进程子进程从 fork 返回点开始继续走而不是从 main 重新开始。所以 if-else 的两个分支分别对应父子进程的「下半场」。值得注意的是子进程会复制父进程的 stdout 缓冲区如果父进程在 fork 之前已经 printf 过但还没刷新子进程可能把父进程的残留内容再打印一遍这就是实验里「输出重复」这类玄学问题的根源。解决方式是 fork 前加 fflush(stdout)或者干脆用 setbuf(stdout, NULL) 关掉缓冲。getpid() 和 getppid() 拿当前进程和父进程的 pid调试父子关系时很好用。Linux 上的 fork 现在用的是写时复制COW机制父进程和子进程初始共享同一份物理内存只有某一方真正要写时才复制页面。这也是 fork 创建子进程很快的原因。实验报告里写「fork 开销小是因为 COW」比只写「复制进程映像」高一个档次这个知识点老师基本都会追问。3.2 exec()替换内存映像失败才返回fork 复制出来的子进程和父进程跑的是同一份代码如果想让它执行另外一个程序就要用 exec 系列函数。exec 会用新程序的内存映像整体替换当前进程替换成功后不返回只有出错才带着错误码回来。pid_t pid fork(); if (pid 0) { /* 子进程执行外部程序 */ execl(/bin/echo, echo, hello from exec, NULL); perror(execl failed); /* 走到这里说明 exec 失败 */ exit(1); } wait(NULL); /* 父进程等待子进程结束 */execl 的第一个参数是程序路径第二个是 argv[0]之后是参数列表最后以 NULL 结尾。子进程调用 execl 成功后被完全替换后面的代码再也不会执行所以 perror 和 exit 必须紧跟在 exec 后面——这两行是保底逻辑exec 失败了要让你知道为什么。见过太多人 exec 后面接着写十行业务代码exec 成功了这些代码永远不执行程序行为跟预期完全对不上。实验里经常用 exec 启动一个子进程去跑排序或计算任务父进程用 wait 等着收结果。如果参数比较多用 execvp 配合数组更灵活不用把参数一个个写死在代码里char *args[] { ./sort_proc, input.txt, NULL }; execvp(args[0], args); /* 按 PATH 搜索可执行文件 */ perror(execvp failed); exit(1);execvp 第一个参数是程序名第二个参数是参数数组最后以 NULL 结尾。路径写绝对路径最稳妥用相对路径时要注意子进程的工作目录继承自父进程你以为的「当前目录」可能不是你以为的那个这是 exec 找不到程序最常见的隐藏原因。3.3 wait()防止僵尸进程回收退出状态子进程退出后不会立刻消失它会残留一个 PCB 让父进程读取退出状态这个状态叫僵尸zombie。父进程不调用 wait/waitpid 回收僵尸就一直在进程表里占位。实验中你执行 ps 看到 defunct 进程九成是没调 wait。int status; pid_t child wait(status); if (WIFEXITED(status)) { printf(child %d exited, code%d\n, child, WEXITSTATUS(status)); } /* 非阻塞轮询版本: 不挂起父进程 */ pid_t ret waitpid(child, status, WNOHANG); if (ret 0) { printf(child still running\n); }wait 是阻塞调用父进程会一直等到任意子进程退出。waitpid 更精细可以指定等哪个子进程加上 WNOHANG 后不阻塞配合轮询可以在父进程继续做别的事的同时检查子进程状态。WIFEXITED 判断子进程是否正常退出WEXITSTATUS 取出退出码这两个宏在实验里用来验证子进程的 exec 是否执行成功。如果父进程同时 fork 了多个子进程就需要在循环里反复调用 waitpid直到返回 -1 表示没有子进程可等了。父进程先于子进程退出时子进程会被 init 进程收养这是孤儿进程orphan跟僵尸完全两回事僵尸是「死了没被收尸」孤儿是「活着但爸爸没了」。实验报告里把这两个概念写清楚比背定义更有说服力。这份资源里的 ProcessControl.c 走的是「模拟」路线它用 PCB 结构体和 state 字段模拟进程从创建到结束的完整生命周期调度算法在内存里操作队列不涉及真实的进程切换。理解 fork/exec/wait 的作用之后再回去看模拟代码会更有感觉——每个被创建出来的 PCB 节点对应现实里一次 fork 产生的子进程state 从 READY 到 RUNNING 再到 FINISHED 的迁移就是真实操作系统里进程状态机的简化版。先看懂真实系统调用再理解模拟代码实验报告里两者互相对照深度立刻不一样。4. 三种调度算法用 C 实现FCFS、SPF、RR 的参数与坑4.1 FCFS顺序执行也要处理 CPU 空闲窗口先来先服务是最朴素的策略谁先到达谁先运行。但实现时有一个容易漏的窗口——CPU 可能空闲。进程 1 在第 0 时刻到达进程 2 在第 5 时刻到达如果进程 1 服务时间只有 2CPU 在 2 到 5 之间是空的这段空闲不能计入任何进程的等待时间。typedef struct { int pid; int arrive; int service; int start; int finish; } Job; void fcfs(Job jobs[], int n) { int cpu_time 0; for (int i 0; i n; i) { if (cpu_time jobs[i].arrive) { cpu_time jobs[i].arrive; /* CPU 空闲, 推进到到达时刻 */ } jobs[i].start cpu_time; cpu_time jobs[i].service; jobs[i].finish cpu_time; printf(P%d: start%d finish%d\n, jobs[i].pid, jobs[i].start, jobs[i].finish); } }cpu_time 变量表示 CPU 的当前时间线。每次调度前先判断下一个进程到达没有没到就把时间线拉到它的到达时刻再把服务时间累加上去。start 是真正开始执行的时刻finish 是结束时刻。平均等待时间 sum(start - arrive) / n平均周转时间 sum(finish - arrive) / n这两个公式是实验报告里必须出现的。很多人的错误是把 start 直接当成上一个 finish无视进程到达时间的间隔算出来的等待时间偏大甚至为负老师一眼就能看出逻辑漏洞。调试时建议打印一行中间结果每个进程的 start 减去 arrive 是多少逐项核对比最后只看平均值更容易定位是哪个进程算错了。4.2 SPF 短进程优先非抢占与抢占是两套写码短进程优先SPF分两类。非抢占式在每次选择进程时从「已到达且未完成」的进程里挑服务时间最短的抢占式也叫 SRTF更进一步每个时刻如果有新进程到达且它的剩余时间比当前运行进程短就立刻切换。实验通常要求实现非抢占版本代码核心是一个选择函数int pick_shortest(Job jobs[], int n, int current_time) { int idx -1; int min 1 30; for (int i 0; i n; i) { if (jobs[i].arrive current_time !jobs[i].done) { if (jobs[i].service min) { min jobs[i].service; idx i; } } } return idx; /* 返回 -1 表示当前没有可运行的进程 */ }这个函数的关键过滤条件是 jobs[i].arrive current_time把「还没到达」的进程排除掉。如果返回值是 -1说明 CPU 需要等待新进程到达此时把 current_time 推进到下一个到达时刻再重新选。服务时间相等时要加第二排序键比如 pid 小的先运行否则每次运行结果可能不同报告里没法复现。抢占版则要在每次新进程到达时比较 remain_time代码复杂一档但核心还是「比较剩余时间谁短谁上」。主调度循环用 while 包住选进程、执行、标记完成、推进时间直到所有进程 done。SPF 的缺点——长进程可能饿死在报告里用一组极端数据一个超长任务加一串短任务演示一遍比空谈理论有说服力得多。4.3 时间片轮转q 的取值决定你是「交互」还是「批处理」时间片轮转RR把 CPU 时间切成固定大小的片每个就绪进程轮流跑一个时间片没跑完就放回队尾。它需要队列支持并且每次执行时用剩余时间递减。#define MAX_PROC 16 void rr(Job jobs[], int n, int quantum) { int remain[MAX_PROC]; int queue[MAX_PROC]; /* 用数组模拟环形队列, 存进程下标 */ int head 0, tail 0; int time 0, done 0; for (int i 0; i n; i) remain[i] jobs[i].service; for (int i 0; i n; i) queue[tail] i; while (done n) { int idx queue[head]; head (head 1) % MAX_PROC; int slice remain[idx] quantum ? remain[idx] : quantum; time slice; remain[idx] - slice; printf(P%d run %d, remain %d, time %d\n, jobs[idx].pid, slice, remain[idx], time); if (remain[idx] 0) { jobs[idx].finish time; done; } else { queue[tail] idx; tail (tail 1) % MAX_PROC; } } }这里用环形数组模拟就绪队列精华是队头出队、未完成的进程从队尾重新入队。slice 取 quantum 和剩余时间的最小值保证最后一个时间片不会超出。while 的终止条件是 done n如果忘记在 remain 0 时累加 done程序会无限循环这是轮转实验最常见的死循环来源。时间片 q 的大小直接影响平均周转时间q 取 1 时响应极快但上下文切换频繁q 取一个大于所有服务时间的值就退化成 FCFS。做实验时建议至少跑两组 q 值比如 q1 和 q4对比数据再把「q 越小响应越快、但切换开销越大」这个 trade-off 写进报告这就是加分项。4.4 数据怎么组织三个算法一张表实验验收时老师最常问的是「三个算法对比结果呢」。数据建议用表格呈现而不是散落的 printf 输出算法参数平均等待时间平均周转时间平均带权周转时间FCFS无.........SPF非抢占无.........RRq1.........RRq4.........平均等待时间和平均周转时间的计算公式上文已经给了。带权周转时间 周转时间 / 服务时间它消除服务时间长短的影响用来衡量调度的相对效率值越接近 1 说明进程越快被完成。几组数据跑出来基本能验证课本结论SPF 的平均等待时间通常优于 FCFSRR 在 q 小的时候响应好但平均周转时间不一定占优。数据对不上理论时先回头查 CPU 空闲窗口有没有处理、时间片 slice 有没有取 min这两个位置是出错高发区。这套「结构体数组 队列 时间统计」的套路印象深一点后面接着做虚拟存储器管理实验时你会发现只是把 PCB 换成了页表项骨架一模一样。5. 进程同步与通信排错管道、信号量与死锁的五个现场5.1 管道阻塞write 端没关干净read 端等到天荒地老管道是最经典的进程间通信方式但实现细节里有个教科书很少强调的规则管道是半双工的数据单向流动读写双方必须把不需要的端关闭否则管道不会出现 EOFread 会一直阻塞。int fd[2]; if (pipe(fd) 0) { perror(pipe); return; } pid_t pid fork(); if (pid 0) { close(fd[0]); /* 子进程关读端 */ write(fd[1], hello, 5); close(fd[1]); /* 写完后关写端 */ exit(0); } close(fd[1]); /* 父进程关写端 */ char buf[16]; int n read(fd[0], buf, sizeof(buf)); /* 读到 5 字节, 或到 EOF */ close(fd[0]);管道在 fork 之后同时被父子进程持有所以每一侧都有两个文件描述符。子进程关闭读端、父进程关闭写端这是「各关各的无关端」的标准姿势。最隐蔽的坑是父进程忘了 close(fd[1])这样系统里仍然存在一个有效的写端父进程自己握着管道的引用计数不为零read 永远不会返回 EOF父进程就卡死在 read 上这种问题表面看像玄学实际就是 fd 引用计数没数清。排查时第一件事就是数清楚 fd 的引用几个进程 fork 出去就有几份读端几份写端除了真正需要的那一个其余全部关掉。5.2 信号量 PV 顺序P 了两次没 V就是永久冬眠信号量用在多进程访问共享资源时保护临界区不被同时进入。POSIX 信号量在支持的平台上可直接用关键是 empty/full 初值和 PV 顺序。#include semaphore.h #define BUFFER_SIZE 4 sem_t empty, full, mutex; /* 初始化: empty4, full0, mutex1, 必须在 fork 之前完成 */ void producer(int id) { while (1) { sem_wait(empty); /* 先申请空位 */ sem_wait(mutex); /* 再锁缓冲区 */ /* 写入一个数据 */ sem_post(mutex); sem_post(full); /* 数据量 1 */ } }正确顺序是先 P(empty) 再 P(mutex)。如果有人把顺序颠倒先抢 mutex 再等 empty当缓冲区满且 mutex 被同一进程持有时其他生产者进不来临界区消费数据的进程即使持有 full 信号量也进不来——所有进程互相等这就是死锁现场。信号量操作的两个原则一是初始值必须反映资源的真实数量empty 是缓冲区空位数full 是已用位数二是每次 P 必须对应一次 V少一次 V 就有一个进程永远等不到。实验里常见的「第二次运行就卡住」现象八成是某个分支里漏了 sem_post。共享内存配合信号量使用时还要注意 sem_init 必须在 fork 之前执行否则只有发起初始化的那个进程能看到正确的信号量状态另一个进程拿到的是未初始化内存里的垃圾值。5.3 死锁的预防与检测资源分配顺序是性价比最高的手段死锁四个必要条件——互斥、持有并等待、不可剥夺、循环等待。实验里最省事的预防手段是破坏「循环等待」给所有资源编号规定每个进程只能按编号递增顺序申请资源。这样环就形成不了因为环意味着存在一个进程申请了编号更大的资源后回头申请更小的这违反规则。实现上就是给每个资源的 acquire 之前加一层编号检查成本极低效果却扎实。检测算法则复杂一些常见做法是维护一张资源分配表和请求表模拟分配过程循环找到能完全满足需求的进程让它运行完释放资源然后继续扫如果在某一步没有任何进程可以被满足说明存在死锁。这个算法本质是个反复扫描的循环写在报告里作为死锁检测的加分实现比只写概念强很多。注意模拟时要用副本数据不要把进程真的结束掉。5.4 五条踩坑实录现象、原因、解决坑 1fork 在 Windows 编译报错现象Code::Blocks 默认的 MinGW 编译器报一堆 undefined reference to fork。 原因fork 是 POSIX 接口Windows 的 C 运行库没有实现。 解决把进程创建相关代码放到 WSL 或 linux 操作系统里编译运行Windows 端只保留不依赖系统调用的调度模拟代码。坑 2fork 之后 printf 输出重复现象子进程把父进程的 printf 内容原样又打了一遍。 原因fork 复制了父进程的 stdout 缓冲区缓冲区里的内容被子进程继承并再次刷新。 解决fork 之前 fflush(stdout)或 setbuf(stdout, NULL) 关掉缓冲。坑 3RR 调度进程「越跑越短」现象轮转调度过程中进程的剩余时间小于实际已执行时间数据对不上。 原因把 need_time 和 remain_time 混成一个字段递减时把总需求也改了。 解决结构体里拆成两个字段need_time 恒定不变只递减 remain_time。坑 4read 管道永远不返回现象父进程 read(fd[0]) 一直阻塞程序挂死。 原因父进程没有关闭自己的写端 fd[1]管道 EOF 永远到不了。 解决fork 后按「各关各的无关端」原则关闭多余描述符数清引用计数。坑 5信号量初始化位置不对现象多个进程共享的信号量状态不一致PV 操作后计数错乱。 原因sem_init 被放在 fork 之后执行只有当前进程能看到初始化结果。 解决信号量必须在 fork 之前完成初始化或用有名信号量保证全局可见。6. 实验验收与调试让结果经得起逐行追问6.1 老师最爱问的三个问题实验验收时光有运行截图不够老师会顺着输出逐行追问。第一个问题平均等待时间是怎么算出来的。你要能当场写出公式并指到代码里对应的变量。第二个问题时间片 q 为什么选这个值。答案是「在小 q 和大 q 之间做了对比实验」把两张表的差别讲出来。第三个问题进程的四个状态在代码里怎么迁移。把 state 字段的赋值点找出来能顺着代码走一遍状态机这一关基本就过了。6.2 调试组合拳gdb 加 printf 双轨我习惯的做法是编译带上 -g 和 -Wallprintf 负责宏观流程gdb 负责微观定位。gcc -Wall -g main.c ProcessControl.c -o process_control gdb ./process_control (gdb) break fcfs (gdb) run (gdb) print jobs[0] (gdb) nextgdb 里最常用的几招break 打断点、run 开跑、next 单步、print 看变量。要是在某个 if 分支里发现 state 值不对print 一眼就能看到。再配合 printf 在关键节点打标记输出里就能看出某个进程卡在了哪个函数哪一行。实验报告里放一段 gdb 截图说明「我如何定位到问题」比放十张运行截图更有说服力。从那以后我做这类实验都强制自己先花一刻钟把 PCB 结构体和三个时间公式写在一张纸上再动键盘。数据结构和验收标准先立住写代码只是把纸上的逻辑翻译成 C。这个习惯救了我很多次希望帮到你。本文还有配套的精品资源点击获取

相关新闻

研究生AI论文写作工具全流程指南:从选题到避坑

研究生AI论文写作工具全流程指南:从选题到避坑

我读研那会儿,最痛苦的一件事不是实验做不出来,而是文献综述写了三个月,最后导师说“综述不像综述,像资料汇编”。现在回头看,问题不完全出在写作能力上,而是我把大量时间花在了检索、翻译、格式整理这些完…

2026/10/1 13:39:24 阅读更多 →
华为三层交换机原理与实战:从VLAN间路由到配置详解

华为三层交换机原理与实战:从VLAN间路由到配置详解

VLAN划了十几个,业务互访却一团乱麻;总部和分公司互联延时高,找来找去发现是二层设备扛了太多不该扛的活。干网络这行,迟早要跟三层交换机打交道。它不是什么新鲜玩意儿,但确实是很多园区网、企业接入层最关键的设备类…

2026/10/1 13:39:24 阅读更多 →
Wi-Fi信号满格却卡顿?一文读懂无线网络防撞机制

Wi-Fi信号满格却卡顿?一文读懂无线网络防撞机制

走进任何一个办公区、商场或家里,你会发现一个普遍现象:手机连着Wi-Fi,明明信号满格,视频却卡成幻灯片;会议室里十几台设备同时联网,网页转圈转到怀疑人生;隔壁邻居的路由器在2.4G频段上开足马力…

2026/10/2 15:50:37 阅读更多 →

最新新闻

大模型本地部署完全指南:从工具选型到推理优化与显存量化

大模型本地部署完全指南:从工具选型到推理优化与显存量化

2026年,本地部署大模型这件事,已经彻底从小圈子的技术玩具变成了很多团队绕不开的刚需。我为什么敢用“刚需”这个词?三个理由:第一是数据隐私,公司代码、客户信息、内部资料,很多人不敢往外传,…

2026/10/2 15:50:51 阅读更多 →
1200次智能体逃逸复盘:生产环境攻击路径与护栏清单

1200次智能体逃逸复盘:生产环境攻击路径与护栏清单

智能体逃逸这件事,圈子里聊了快两年,但真正让我意识到“事态严重”的,是最近一次复盘:1200 个实例在外网环境下成功攻破了生产环境的防护边界。你没看错,不是 12 个,不是 120 个,是 1200 个。这…

2026/10/2 15:50:51 阅读更多 →
AI热搜深度解读:从智能体训练到多AI协作的工程化实战

AI热搜深度解读:从智能体训练到多AI协作的工程化实战

今天的AI热搜榜上,有价值的信号其实非常密集:既有DeepSeek公开智能体训练新方法这样的硬核技术新闻,也有"AI Agent怎么扛并发"这种典型的工程化焦虑,还有AI短剧、AI视频画质修复、AI产品经理角色变化等贴近业务落地的词…

2026/10/2 15:50:51 阅读更多 →
孩子对CSP-J2、CSP-S2爆零经历有抵触情绪,怎么引导复盘

孩子对CSP-J2、CSP-S2爆零经历有抵触情绪,怎么引导复盘

引导抵触爆零复盘的孩子,核心是先完全接住情绪,再用游戏化的低压力方式绕开“翻旧账”的抵触点,全程不指责、不贴标签,把复盘变成孩子自己主动参与的“寻宝闯关”,完全不占用太多校内时间。 🧸 第一步&…

2026/10/2 15:50:51 阅读更多 →
CSP-J2、CSP-S2孩子爆零后如何制定孩子恢复信心的计划

CSP-J2、CSP-S2孩子爆零后如何制定孩子恢复信心的计划

CSP-J2、CSP-S2爆零后的信心恢复,不是"安慰两句"就能解决的,需要一份有节奏、可执行、不占校内时间的计划。下面这份计划按"情绪→掌控感→归因→状态→预期"五步走,全程单日不超过30分钟,你可以直接照着执行…

2026/10/2 15:50:51 阅读更多 →
AI智能体产品开发实战:从脚手架到护城河的工程化路径

AI智能体产品开发实战:从脚手架到护城河的工程化路径

1. 从 Grok Bot 一个月造出爆款说起:AI 智能体产品的演化逻辑1.1 一个月造出爆款,真正值得关注的不是速度Grok Bot 一个月做出爆款这件事,圈内人第一反应往往是“团队执行力强”或者“踩中了风口”。但如果你真正做过 AI 智能体产品&#xff…

2026/10/2 15:49:50 阅读更多 →

日新闻

从零搭建AI工程化:模型之外的完整闭环

从零搭建AI工程化:模型之外的完整闭环

先搞清楚一件事:从零开始做 AI 工程化,难的从来不是调模型、写提示词,而是把一套原型 Demo 变成长得像是“正经系统”的东西。你手里可能已经有了能跑通的代码,也可能刚读完一些概念,但真到了要把它变成可维护、可观测…

2026/10/2 0:00:20 阅读更多 →
大模型训练显存估计与混合精度训练实战指南

大模型训练显存估计与混合精度训练实战指南

1. 大模型训练显存估计与混合精度训练详解显存不够用,几乎是每个做大模型训练的人都会撞上的第一堵墙。你可能也经历过:模型代码写完了,数据管道跑通了,满心欢喜地按下训练启动脚本,结果几秒钟后终端弹出一行红字——C…

2026/10/2 0:00:20 阅读更多 →
小样本学习数据集选型指南:27个真正可用的高质量数据集

小样本学习数据集选型指南:27个真正可用的高质量数据集

1. 小样本学习的“弹药库”:为什么你总在找数据集,却总找不到真正能用的? 小样本、数据集——这两个词最近半年在我处理的200多个AI项目咨询里,出现频率排进前三。不是模型调不好,不是代码写不对,而是卡在…

2026/10/2 0:00:20 阅读更多 →

周新闻

如何划分训练/验证集:Spirula Studio五种eval_mode策略详解

如何划分训练/验证集:Spirula Studio五种eval_mode策略详解

如何划分训练/验证集:Spirula Studio五种eval_mode策略详解 【免费下载链接】spirula-studio Cross-vendor 3D Gaussian Splatting trainer - video to splat to mesh, Vulkan or CUDA. 项目地址: https://gitcode.com/GitHub_Trending/sp/spirula-studio Sp…

2026/10/1 19:40:48 阅读更多 →
SEO怎么推广速查手册新手避坑实战指南

SEO怎么推广速查手册新手避坑实战指南

SEO怎么推广速查手册新手避坑实战指南 模板网站太丑不够用?别急着加滤镜,那是治标不治本。很多老板盯着后台流量掉得眼红,却还在纠结首页Banner的圆角是不是3像素。这就像穿着西装去挖土,姿势不对,努力白费。我整理这份 速查手册…

2026/10/1 19:41:40 阅读更多 →
FireRed-OpenStoryline少样本仿写深度解析:AI Agent如何复刻你的独特文案风格与节奏

FireRed-OpenStoryline少样本仿写深度解析:AI Agent如何复刻你的独特文案风格与节奏

FireRed-OpenStoryline少样本仿写深度解析:AI Agent如何复刻你的独特文案风格与节奏 【免费下载链接】FireRed-OpenStoryline FireRed-OpenStoryline is an AI video editing agent that transforms manual editing into intention-driven directing through natural language …

2026/10/1 20:05:24 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/2 10:36:31 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/2 5:26:06 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/2 6:09:11 阅读更多 →