Linux多线程编程从入门到实践:线程概念、同步与常见坑
1. 线程到底是什么从进程说起1.1 进程的老概念和它的痛点很多人第一次学Linux编程都会背概念进程是资源分配的最小单位进程有独立的地址空间、独立的PCB、独立的文件描述符表……这话没错但放到实际写程序的时候你会发现进程有一个非常尴尬的地方——太“重”了。我最早写多进程网络服务时一个客户端连上来就fork一个子进程去处理。跑起来倒是也正常但再仔细一观察内存占用蹭蹭往上涨进程切换的CPU开销也肉眼可见地变大。尤其当业务里有大量需要共享的数据比如一个全局计数器、一份配置信息时多进程之间的通信就得靠管道、消息队列、共享内存。每次同步还要考虑加锁写起来又繁又容易出错。更头疼的是fork出来的子进程虽然继承了父进程的内存映像但它们是独立的副本父子之间改一个变量互相看不见。你想让好几个并发执行流共享同一份数据用多进程纯粹是给自己找麻烦。于是线程就出现了。Linux下线程其实可以理解成一个“轻量级进程”它自己维护一个栈和执行上下文但和同一进程里的其他线程共享地址空间、全局变量、文件描述符、信号处理器等一大堆资源。这样一来多个执行流之间共享数据变得极其简单代价是——你得操心同步否则分分钟被数据竞争教做人。1.2 线程在Linux内核里的真实身份这里要澄清一个很多人困惑的点Linux内核里其实没有独立的“线程”数据结构。内核认为线程本质上是“共享了地址空间的进程”所以底层仍旧用task_struct来表示。我们常说的“线程”是用户态pthread库POSIX线程通常就是glibc里的libpthread提供的抽象。也就是说你在用户态调用pthread_create最终会执行一个clone系统调用往里传一堆CLONE_*标志位告诉内核“我要创建一个新task但下面这些资源我要和父task共享”。比如CLONE_VM表示共享地址空间CLONE_FILES表示共享文件描述符表CLONE_SIGHAND表示共享信号处理函数。从内核调度器角度看线程和进程都是task调度平权。理解这一点对你很有用。你会发现“线程切换成本低”并不是凭空来的而是因为它们共享了大部分资源切换时不需要切换MMU映射、不需要刷新TLB当然现代CPU有PCID优化但大方向上还是比进程切换轻。下次如果面试官问你“Linux中线程是什么”你可以回这个层次的理解比单纯的“轻量级进程”要深入一截。1.3 线程之间到底共享什么、独享什么用一个生活类比进程是一个公司线程是这个公司里的员工。公司有独立的办公地址、独立账本、独立门禁。员工们在同一个办公室里办公都看同一块白板全局变量都能用同一个打印机文件描述符但每个人有自己的座位、自己手里的笔记本栈也记得自己当前在干什么活寄存器上下文、程序计数器。具体到Linux的pthread语义线程之间共享线程各自独享地址空间代码段、数据段、堆、动态库映射线程栈局部变量、函数调用栈帧全局变量和静态变量线程IDtid打开的文件描述符列表寄存器上下文程序计数器、栈指针等信号处理函数errno 变量线程局部存储当前工作目录、用户ID、用户组ID线程调度优先级可独立设置进程PID和父进程PID信号掩码可用pthread_sigmask单独设置注意最后两行。很多人写代码时默认“线程和进程一样”或者“线程啥都是共享的”这俩都会出问题。比如errno明明是全局的但线程库里把errno做成了线程局部存储这样两个线程同时出错时不会互相覆盖你才能分别拿到自己的错误码。如果你误以为errno是共享的在多线程里看到奇怪的值排查方向就错了。再比如线程栈默认线程栈大小通常是8MB可以通过pthread_attr_setstacksize修改。这个栈是独立分配的所以线程里的局部变量在逻辑上互不相干。但堆上的东西malloc出来的是共享的因为你用的是同一个进程堆。这也就引出了多线程编程的第一定律缺省情况下栈上自享堆上共享全局共享所以堆和全局变量统统要注意同步。2. 线程控制的核心API创建、等待、终止、分离2.1 pthread_create创建线程的细节与参数创建线程的函数长这样#include pthread.h int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg);四个参数逐个拆解thread输出参数线程创建成功后这里会写入一个不透明的线程ID。注意这个ID只在进程内有效不要和内核tid混淆更不要和getpid()搞混。attr线程属性传NULL表示默认属性。需要定制栈大小、调度策略、分离状态时就传一个初始化好的pthread_attr_t。start_routine线程入口函数一个接收void返回void的函数。函数返回就代表线程正常结束。arg传给入口函数的参数。这是一个void*所以可以传整数得强转也可以传结构体指针。我踩过最大的坑是给线程传栈上局部变量的地址。比如void start_threads() { int id 1; pthread_t t; pthread_create(t, NULL, worker, id); }这里的id是start_threads栈上的局部变量线程worker还没来得及读它start_threads就返回了这块栈空间可能被复用线程拿到的id就是不可预测的垃圾值。正确做法是传堆上的内存或者干脆把整数直接塞进void*参数里比如pthread_create(t, NULL, worker, (void *)(long)1);在线程函数里再转回来void *worker(void *arg) { long id (long)arg; // ... }这种写法在64位Linux下是完全安全的因为long和void*等宽。能用简单方式就别搞复杂结构这算多线程入门第一课。attr参数在大多数场景下都可以置空但有一个场景我建议显式设置你想控制线程栈大小时。默认栈8MB对某些深度递归算法不够用可以用如下方式设置pthread_attr_t attr; pthread_attr_init(attr); pthread_attr_setstacksize(attr, 16 * 1024 * 1024); // 16MB pthread_create(t, attr, worker, NULL); pthread_attr_destroy(attr);注意attr在pthread_create后就不需要了destroy即可。另外千万别在创建多个线程时复用同一个attr并同时修改属性设置最好集中一次性完成。2.2 线程结束的三种姿势别搞混一个线程可以通过三种方式终止入口函数调用pthread_exit(void *retval)指定返回值线程立即终止。入口函数执行return返回void*作为返回值效果和pthread_exit等价。被其他线程调用pthread_cancel强制取消。特别容易出错的是在线程入口函数里调用exit()。exit()是进程级的它会结束整个进程所有线程全被带走。我见过一个线上服务某个工作线程在处理请求时遇到错误条件直接exit(1)结果整个服务崩溃重启排查了半天才找到罪魁祸首。记住线程里要退出当前线程用pthread_exit或return要终止进程那是主线程或专人干的事。再补充一个冷门但实用的点如果main函数里调用了pthread_exit那么进程并不会立刻退出所有其他线程会继续运行因为main所在的线程退出了但进程还存活。如果main直接用return或exit退出进程会终止所有还在运行的线程都会被立刻杀死。很多跑多线程程序的人发现主线程一旦结束工作线程还没跑完就消失了原因就是这个。2.3 线程资源回收与pthread_join默认情况下线程退出后其资源不会自动释放需要另一个线程调用pthread_join来“收尸”。如果不join线程退出后它会变成一个僵尸类似进程的僵尸态累积多了会导致ID耗尽pthread_create失败报EAGAIN。pthread_join的典型用法ret pthread_join(tid, retval);tid要等待的线程ID。retval输出参数用来接收被等待线程的返回值。如果线程是被pthread_cancel取消的返回PTHREAD_CANCELED。返回值0表示成功非0表示出错ESRCH表示找不到线程IDEDEADLK表示死锁比如自己join自己。join相当于“阻塞等待线程结束并回收资源”有点类似进程的wait/waitpid。使用join还有一个隐含的同步效果只有join返回后你才能确定线程已经跑完了才好去读它写好的数据。所以不要把join只当成资源回收它也是线程间同步的一种原始方式。有个细节join只能对“可join”的线程使用。如果一个线程已被设为detached分离状态它的资源退出后由系统自动回收你去join会返回EINVAL。别把分离线程的ID还留着去join那是白费力气。2.4 pthread_detach什么时候需要让线程自生自灭如果一个线程不需要被别人等待那就在创建后立刻把它设置成分离状态pthread_detach(tid);或者创建时通过attr设置PTHREAD_CREATE_DETACHEDpthread_attr_setdetachstate(attr, PTHREAD_CREATE_DETACHED); pthread_create(t, attr, worker, NULL);两种方式等价。你用第二种可以避免线程已经退出后再detach导致的竞争问题。注意pthread_detach只决定资源回收方式并不影响线程是否继续运行。分离线程退出后资源由系统自动回收你再也不能join它了它的返回值也无从获取。实务中像线程池里的工作线程、定时器线程、后台监控线程基本都会设置为分离状态。而主流程需要结果并行计算通常要走join。需要特别提醒的是就算分离线程也不代表“不用管它”。它依然共享进程的地址空间如果它访问了非法内存照样把整个进程崩掉。分离只解决资源回收不解决错误隔离。3. 线程同步概念之外的第一个大坑3.1 为什么必须同步一段代码引发的血案聊线程控制绕不开同步。如果你写一个多线程程序所有线程只读不写共享数据那倒还好一旦发生写马上就会出乱子。原因很简单现代CPU和编译器为了性能会对指令重排而且内存操作不是原子性的。比如下面这段代码// 全局变量 long counter 0; void *inc(void *arg) { for (int i 0; i 1000000; i) { counter; } return NULL; }创建两个线程同时跑正常预期counter最终是2000000。但实际运行你可能会得到180万甚至更离谱的值。因为counter在机器层面是“读-改-写”三个操作两个线程可能同时读到相同旧值各自加1再写回把一个增量覆盖了。这种问题用完全公平的线程调度也躲不开因为它本质上是并发写共享变量的数据竞争问题。3.2 互斥锁保护临界区的正确姿势最基础的工具是互斥锁pthread_mutex_t。用起来四步走pthread_mutex_t mutex PTHREAD_MUTEX_INITIALIZER; // 或者动态初始化 pthread_mutex_init(mutex, NULL); // 加锁 pthread_mutex_lock(mutex); // 临界区只做必要操作 counter; // 解锁 pthread_mutex_unlock(mutex);互斥锁的核心思想是同一时刻最多只有一个线程能持有锁其他想拿锁的线程会阻塞等待。这相当于给临界区加了一扇门门里一次只能进一个人。但要注意加锁粒度。锁的区域太大所有线程都挤在门口排队性能退化成串行锁的区域太小保护不住数据。我常用的经验是在共享变量周围尽可能只锁必要的读写不锁那些耗时的IO或计算。比如把一个复杂的业务逻辑整个锁住看起来安全了实际上性能惨不忍睹而且后面调试死锁会让你崩溃。还有几个容易翻车的点忘记解锁尤其是函数中间有return或goto跳出的分支。建议检查所有路径。同一线程对同一非递归互斥锁重复加锁会死锁。标准pthread_mutex_t是快速锁不是可重入锁自己锁自己就是死锁。需要重入就改用pthread_mutexattr_settype的PTHREAD_MUTEX_RECURSIVE。加锁顺序不一致多把锁时很容易相互等待产生死锁。后面会细说。3.3 条件变量等待某个条件成立的正确姿态互斥锁只解决了“互斥”没解决“等待”。经典场景生产者-消费者。消费者要等队列里有数据才去取没数据时如果循环轮询白白烧CPU。条件变量就是为此设计的。pthread_mutex_t mutex PTHREAD_MUTEX_INITIALIZER; pthread_cond_t cond PTHREAD_COND_INITIALIZER; // 消费者线程 pthread_mutex_lock(mutex); while (queue_empty()) { pthread_cond_wait(cond, mutex); } item pop_item(); pthread_mutex_unlock(mutex); // 生产者线程 pthread_mutex_lock(mutex); push_item(); pthread_cond_signal(cond); // 唤醒一个等待线程 pthread_mutex_unlock(mutex);这里有个必须刻进骨子里的细节pthread_cond_wait不是一个纯“睡眠”调用它在阻塞之前会先自动释放mutex等被唤醒后再尝试重新获得mutex然后返回。所以调用wait时的前提必须是“已经持有mutex”这个顺序错了程序就彻底乱套。为什么要用while循环而不是if因为pthread_cond_signal可能唤醒多个线程broadcast而且信号还可能“虚假唤醒”甚至等待者被唤醒后锁又被别人抢走。用while重新判断条件才保险。这个理由光靠记不牢写进代码里才是正道。条件变量和互斥锁配合使用的实质是互斥锁保护条件本身判断队列非空必须加锁条件变量让线程在条件不满足时沉睡等待而不是忙轮询。理解了这层关系再写生产者-消费者就会顺畅很多。4. 常见问题与排查技巧实录4.1 编译链接报错undefined reference to pthread_create新手最容易撞上的问题编译命令少写了-lpthread。在较新的glibc上pthread函数已经合并到libc里单线程编译可能也能过但严谨起见还是要显式链接。我一般这样写gcc -Wall -Wextra -o app app.c -lpthread注意链接库的位置要放在源文件后面。如果你用的CMake记得在target_link_libraries里加上pthread。敲错大小写也会报错——是pthread不是Pthread。还有一种情况你用了链接顺序在没有把库放在引用它的.o目标文件之后也会出现undefined reference。把-lpthread挪到最后一切灰飞烟灭。4.2 线程访问了已释放的内存多线程程序里最常见的隐性崩溃就是悬垂引用。比如在线程A里malloc了一块缓冲区把这个指针传给线程B之后线程A完成了任务人家调用了free线程B还在用这个指针轻则读到垃圾数据重则直接段错误。排查这种问题最容易的办法不是盯着代码看而是用AddressSanitizergcc -fsanitizeaddress -g -o app app.c -lpthread ./app如果存在use-after-freeASan会非常明确地指出是哪个地址、哪一行释放的、哪一行继续访问的。比你自己猜效率高一倍不止。日常开发多线程程序我几乎默认开着大象、ASan、ThreadSanitizer测一轮再上线。ThreadSanitizer专门检测数据竞争gcc -fsanitizethread -g -o app app.c -lpthread跑一下测试凡是它有告警的地方基本就是你的共享变量没加锁。4.3 主线程提前退出子线程跟着团灭我刚入门时写过一段代码main里创建了一个线程去后台写日志然后main继续干别的干完直接return。结果日志文件里内容断断续续很多条没写进去。原因前面讲过main返回等于整个进程退出所有线程立刻被终止后台线程根本来不及把缓冲区的数据落盘。解决思路分两种。一是main里在退出前join那个后台线程确保它干完活pthread_create(log_tid, NULL, log_writer, NULL); // ...干别的... pthread_join(log_tid, NULL); return 0;二是如果你不想阻塞等待可以给后台线程设置分离状态但必须在main函数最后调用pthread_exit让main线程自己退出而进程继续存活pthread_detach(log_tid); // ...干别的... pthread_exit(NULL); // 注意这里永远执行不到 return 0后面这个方式常用于服务型程序main线程本身就是用来监控各个线程的不参与业务计算。它通过pthread_exit退出自己这层“老板线程”但公司进程还在。4.4 死锁现象、定位与预防死锁太常见了。代码逻辑看起来没毛病跑起来偶尔卡死。最典型的场景是两把锁交叉等待线程1持锁A等待锁B线程2持锁B等待锁A。于是两边谁都等不到程序挂起。排查死锁可以试试gdbgdb -p pid在gdb里执行info threads查看每个线程的栈(gdb) thread apply all bt你能看到每个线程卡在哪个锁的lock调用上。再用frame切换线程栈看它已经持有哪把锁。找到“两把锁在互相等”的证据基本就锁定问题了。预防死锁有几种工程实践。最有效也最无脑的是“锁顺序一致”所有线程获取多把锁时都按完全相同的顺序拿。比如约定必须先拿锁A再拿锁B线程2也按这个顺序就不会交叉等待。其次是使用trylock拿不到就释放已持有的锁退避重试。不过trylock在多线程复杂场景下容易产生活锁务实一点优先做锁顺序约定。另一个根治思路是缩小锁粒度。如果两个共享数据可以在逻辑上合并成一把锁保护就不存在锁顺序问题了死锁概率大大降低。毕竟“没有多把锁就没有交叉等待”。5. 我的一点实操体会最开始接触线程我老想把线程想成一堆互不相干的小进程结果总在共享变量上翻车。后来我把思考方式改成了“同一进程内的多个执行单元共享是常态隔离是意外”再去写同步逻辑就顺多了。尤其那句“能共享的都共享了不能共享的只有栈和上下文”基本解释了线程绝大多数行为模式。给新入坑的同学几个建议。第一多线程入门阶段优先掌握线程创建、join、detach、互斥锁、条件变量这几样够覆盖90%场景。信号量、读写锁、自旋锁等可以后续按需深入别一上来贪多。第二能用消息传递或线程池封装调度就别到处裸写pthread。裸写pthread意味着大量lock/unlock散落在业务代码里出bug概率随代码量线性上升。我在模拟项目X里就是先把线程池封装好业务线程只管提交任务彻底把创建、销毁、同步的细节关进了笼子。第三调试线程问题时多依赖工具而不是肉眼。TSan、ASan的顺序是先跑TSan查数据竞争再跑ASan查内存错误最后实在没办法才上gdb慢慢看锁。有一次线上服务间歇性阻塞我用gdb attach看线程栈发现两个线程分别卡在read和mutex_lock上再结合当时的业务日志很快定位到是某个持锁路径里做了一次长时间阻塞IO。这把锁的范围改成不覆盖IO操作后问题彻底消失。这个经历给我的启发是线程问题的根源往往不在你“找不到共享数据在哪”而在你“不小心把非必要资源也框进了临界区”。写多线程没有银弹。概念背熟只是起点真正的分水岭是你对“共享”的敬畏共享变量要加锁锁的粒度要小锁的顺序要统一线程的资源要回收。把这四条刻在脑子里你的多线程程序大概率能跑得又稳又顺。

相关新闻

华为交换机配置片段实战:VLAN、SSH、Eth-Trunk与安全加固

华为交换机配置片段实战:VLAN、SSH、Eth-Trunk与安全加固

最近在整理交换机的配置模板时,我翻了一遍过去两年攒下来的华为交换机配置片段,发现很多当时费劲查文档才搞定的命令,现在看就是几行固定套路。说实话,配置片段这个东西,单看一条命令谁都会敲,难的是怎么把…

2026/10/15 4:20:48 阅读更多 →
PCA9685 16路PWM调光:从寄存器到伽马校正的实战指南

PCA9685 16路PWM调光:从寄存器到伽马校正的实战指南

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

2026/10/15 4:19:48 阅读更多 →
达梦数据库认证机制深度解析:从disql登录到用户权限的七步链路

达梦数据库认证机制深度解析:从disql登录到用户权限的七步链路

1. 为什么达梦数据库的认证练习不是“背命令”,而是必须亲手拆解的底层逻辑课“达梦数据库认证练习”这八个字,放在今天的技术圈里,听起来像一份标准考纲、一套应试题库,甚至有人直接把它等同于“把dmctl、disql这些命令敲熟就行”…

2026/10/15 4:19:48 阅读更多 →

最新新闻

火山引擎智能数据洞察平台v2.0工程实践深度解析

火山引擎智能数据洞察平台v2.0工程实践深度解析

简介:本资源是火山引擎官方发布的《智能数据洞察平台v2.0》核心介绍PPT,面向企业数据平台建设者、BI工程师、数据分析负责人及数字化转型决策者,系统解析该平台在跨源融合、自助建模、AI增强分析与嵌入式BI等关键场景下的技术架构与落地能力。…

2026/10/15 4:59:06 阅读更多 →
基于SpringBoot+Vue的校园体育资源共享与运动爱好者交流平台设计与实现

基于SpringBoot+Vue的校园体育资源共享与运动爱好者交流平台设计与实现

选题背景与意义 随着我国高等教育事业的持续发展和“健康中国”战略的深入推进,高校体育教育逐渐从传统的课堂教学模式向多元化、个性化、信息化方向转型。校园体育资源作为高校育人体系的重要组成部分,不仅承载着增强学生体质、培养健康生活方式的功能&…

2026/10/15 4:59:06 阅读更多 →
金融方面的证书有哪些含金量高的?按岗位分赛道的选择思路

金融方面的证书有哪些含金量高的?按岗位分赛道的选择思路

金融领域的证书很多,宣传口径也很杂。有人把从业资格和CFA放在一张表里比,有人把培训结业证说成"国家认可",还有人暗示考下某个证就能进投行。这些说法往往忽略了一个前提:证书的含金量,取决于它本身的制度性…

2026/10/15 4:59:06 阅读更多 →
剑侠世界4:无限定档10.15公测!开服福利奖励攻略

剑侠世界4:无限定档10.15公测!开服福利奖励攻略

剑侠世界4:无限于10月15日全平台公测,预下载也已经正式开启。10 月 14 日 10 点起全平台开放预下载,同步开启服务器预创角。PC 端玩家预创角成功后,还能进入独立试玩场景,提前熟悉各武器的技能手感和外观效果。要注意首…

2026/10/15 4:59:06 阅读更多 →
xtu C语言基础-试除法判断素数

xtu C语言基础-试除法判断素数

//试除法判断素数 int is_prime(int n){if(n<2) return 0; if(n2) return 1;if(n%20) return 0; //除2以外所有偶数都不是素数//排除了偶数之后只用遍历奇数for(int i3;i*i<n;i2){ //i*i可以避免浮点数运算if(n%i0) return 0;}return 1; }

2026/10/15 4:59:06 阅读更多 →
静态路由实现全网可达:从路由表原理到配置与排错

静态路由实现全网可达:从路由表原理到配置与排错

做网络项目最烦的是什么&#xff1f;设备连好线、接口全亮&#xff0c;结果PC之间互相ping不通&#xff0c;而且怎么查都看不出问题。干这行久了你就明白&#xff0c;八成是路由表没配周全——数据包走到中间某台路由器&#xff0c;转发表里没有目标网段&#xff0c;报文直接被…

2026/10/15 4:58:06 阅读更多 →

日新闻

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

1. 为什么选择容器化方式部署 LoRa 网络服务LoRa 物联网项目落地时&#xff0c;网络服务器是整个链路的核心枢纽。它负责接收网关上报的数据包、完成去重与解密、再把有效载荷分发给上层应用。早期大家习惯把网络服务器直接装在物理机上&#xff0c;依赖一堆系统库和特定版本的…

2026/10/15 0:00:46 阅读更多 →
共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

1. 共享推理服务里&#xff0c;扩缩容到底难在哪做过大模型推理服务部署的人&#xff0c;大概都经历过这样的场景&#xff1a;一个团队共用一套推理集群&#xff0c;A 业务跑的是 7B 的小模型&#xff0c;B 业务跑的是 72B 的大模型&#xff0c;C 业务白天流量高、晚上几乎归零…

2026/10/15 0:00:46 阅读更多 →
Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

1. 引子&#xff1a;一次内核恐慌引发的追查先从一个真实场景说起。某次我给一台老旧的嵌入式设备折腾系统裁减&#xff0c;为了把启动时间压进两秒以内&#xff0c;我手贱地把一串自认为“没用”的 systemd 服务给 disable 了&#xff0c;其中就包括systemd-remount-fs.servic…

2026/10/15 0:00:46 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介&#xff1a;基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码&#xff0c;面向计算机相关专业课程设计与期末大作业学生&#xff0c;以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程&#xff0c;…

2026/10/14 3:30:28 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程&#xff1a;键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化&#xff0c;十个新手有八个栽在"往输入框里填东西"这件事上&#xff1a;要么填不进去&#xff0c;要么填了一半&#xff0c;要么直接把原来内容追加在后面。这背后的根因&…

2026/10/14 16:30:29 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程&#xff1a;阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀&#xff1a;什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面&#xff0c;跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/14 3:29:58 阅读更多 →

月新闻

我发现了一个新思路:用 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/15 0:14:36 阅读更多 →
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/14 22:45:47 阅读更多 →
黑夜航拍船只数据集训练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/14 7:53:34 阅读更多 →