当前位置:首页>Linux>嵌入式 Linux 开发|线程知识点大总结

嵌入式 Linux 开发|线程知识点大总结

  • 2026-03-26 20:31:14
嵌入式 Linux 开发|线程知识点大总结

Hello大家好:

这是一篇面向嵌入式 Linux 应用开发者的线程系统总结。

里面涉及到的部分有:线程相关概念、API、同步、工程设计、排错调优、笔试题、面试题、编程题。

希望大伙儿阅读这篇文章时,不是单纯“背几个 pthread 函数”,而是把 线程基础、同步机制、协作模型、工程化设计、调试排错、常考题都能熟练运用起来。

先说结论:线程到底学什么?

很多朋友在一开始学线程时,容易陷入两个误区:

第一,只记 API。 第二,只会写 demo,不会做工程。

而嵌入式 Linux 线程真正要掌握的,是下面这条主线:

创建线程 → 理解共享 → 发现竞争 → 用锁保护 → 用条件变量协作 → 做生产者消费者 → 做工程化线程模型 → 能调试和排错

也就是说,线程不是孤立的语法点,而是一整套并发设计能力。

话不多说,咱们直接进入主题。

一、线程模块在嵌入式 Linux 应用开发中的位置

在嵌入式 Linux 应用开发中,线程通常用于这些场景:

  • 串口接收线程

  • 网络收发线程

  • 传感器采集线程

  • 协议解析线程

  • 数据处理线程

  • 日志线程

  • 存储线程

  • 心跳/看门狗线程

  • UI 线程或业务线程

  • 后台维护线程

为什么要用线程?

因为嵌入式系统中,不同任务的特征往往不一样:

有的任务强调实时采集

有的任务计算量大

有的任务会阻塞在 I/O

有的任务要长期后台运行

有的任务只能异步处理

如果全部写在一个主循环里,代码容易变得阻塞、耦合、难维护。 这时线程就提供了一种非常重要的组织方式:把不同职责拆开并发执行。

二、线程与进程:这是线程学习的第一道门槛

1. 进程是什么?

进程是系统进行资源分配的基本单位。 每个进程拥有自己独立的地址空间、资源、文件描述符表、内存映射等。

2. 线程是什么?

线程是 CPU 调度的基本单位。 线程运行在进程内部,同一个进程可以拥有多个线程。

3. 同一进程内线程共享什么?

同一进程中的多个线程共享:

  • 代码段

  • 全局变量

  • 静态变量

  • 文件描述符

  • 地址空间

  • 信号处理设置

4. 每个线程私有什么?

每个线程私有:

  • 线程栈

  • 寄存器上下文

  • 程序计数器

  • 线程 ID

  • 线程局部存储

5. 为什么线程比进程“轻”?

因为线程不需要重新建立完整的地址空间,创建和切换开销通常小于进程。 这也是线程适合做高频协作任务的重要原因。

三、并发与并行:面试高频基础点

很多人把这两个词混着用,其实不一样。

1. 并发

多个任务在时间上交替推进。 单核 CPU 也可以并发,因为线程会被调度器轮流执行。

2. 并行

多个任务在同一时刻真正同时执行。 通常依赖多核 CPU。

3. 在嵌入式 Linux 中如何理解?

单核平台:主要是并发

多核平台:可以并发,也可以并行

这意味着线程程序的执行顺序往往不确定。 所以多线程问题的本质,往往不是“语法错”,而是“时序不可预测”。

四、POSIX 线程库:嵌入式 Linux 用户态线程的核心

嵌入式 Linux 应用层最常用的是 POSIX 线程,也就是 pthread。

头文件:

#include <pthread.h>

编译时通常需要链接线程库:

gcc test.c -o test -lpthread

有些环境也常见:

gcc test.c -o test -pthread

五、线程创建、退出、回收:最基础但必须扎实

1. 创建线程:pthread_create

函数原型:

int pthread_create(pthread_t *thread,                   const pthread_attr_t *attr,                   void *(*start_routine)(void *),                   void *arg);

参数解释:

thread:返回线程 ID

attr:线程属性,通常先传 NULL

start_routine:线程入口函数

arg:传给线程函数的参数

线程函数的标准形式

void *thread_func(void *arg){    return NULL;}

最简示例

#include <stdio.h>#include <pthread.h>void *worker(void *arg){printf("worker thread running\n");return NULL;}int main(void){      pthread_t tid;      pthread_create(&tid, NULL, worker, NULL);      pthread_join(tid, NULL);return 0;}

2. 等待线程结束:pthread_join

函数原型:

int pthread_join(pthread_t thread, void retval);

作用:

等待指定线程结束

回收线程资源

获取线程返回值

如果不回收 joinable 线程,线程资源可能泄漏。

3. 线程退出的几种方式

方式一:线程函数 return

最自然、最常见。

方式二:pthread_exit

显式退出当前线程。

方式三:被取消

由其他线程调用 pthread_cancel 请求取消。

4. 分离线程:pthread_detach

如果线程不需要被 join,可以分离。

pthread_detach(tid);

特点:

线程结束后自动释放系统资源

分离后不能再 pthread_join

适用场景

后台工作线程、无需返回值的独立线程。

不适用场景

主线程需要知道它何时结束,或者要获取它的返回值。

六、线程传参:看似简单,实则极易出错

线程入口只有一个参数:

*void arg

所以所有参数传递都要围绕这个 void * 展开。

1. 传单个整型参数

int num = 100;pthread_create(&tid, NULL, worker, &num);

线程中:

void *worker(void *arg){      int value = *(int *)arg;return NULL;}

注意:要保证这个地址在线程使用期间有效。

2. 传多个参数:工程中最常见的是结构体

typedef struct{      int id;      char name[32];      int interval_ms;  }thread_arg_t;

传入线程:

thread_arg_t arg;pthread_create(&tid, NULL, worker, &arg);

线程中:

thread_arg_t *p = (thread_arg_t *)arg;

为什么结构体最常用?

因为线程函数只能接收一个参数,而真实业务常常不止一个参数。

3. 经典错误:循环变量地址复用

错误示例:

for (i = 0; i < 5; i++) {           pthread_create(&tid[i], NULL, worker, &i);}

这会导致多个线程拿到同一个 i 的地址,结果经常错乱。

正确做法:

给每个线程单独准备参数

用数组保存每个参数

或为每个线程动态分配参数

七、线程返回值:不仅能干活,还能带结果回来

线程返回值本质是 void *。

void *worker(void *arg){     int *result = malloc(sizeof(int));     *result = 123;return result;}

主线程接收:

void *ret = NULL;pthread_join(tid, &ret);int value = *(int *)ret;free(ret);

重要警告:不能返回局部变量地址

错误示例:

void *worker(void *arg){int result = 123;return &result;   // 错误}

因为局部变量在函数返回后生命周期结束,返回其地址是典型野指针错误。

八、线程共享内存:线程强大的地方,也是出bug最多的地方

线程之间为什么通信方便? 因为它们共享同一个进程地址空间。

这意味着:

主线程改全局变量,子线程能看到

子线程往堆里写数据,其他线程也可能访问

这很方便,但也很危险。

共享数据的典型类型

  • 全局变量

  • 静态变量

  • 堆上的对象

  • 链表、队列、哈希表

  • 全局配置结构体

  • socket/串口句柄状态

  • 业务状态机变量

真正的风险:多个线程同时操作同一份数据

如果多个线程并发访问共享变量,而且至少有一个线程在写,那么如果没有同步保护,就可能发生:

  • 数据竞争

  • 丢失更新

  • 中间态被读到

  • 内存破坏

  • 时序依赖 bug

九、什么是数据竞争?为什么 counter++ 不安全?

很多初学者觉得下面这句没问题:

counter++;

但实际上它通常不是一个原子操作,而是可以分成:

读 counter 加 1

写回去

如果两个线程同时做,就可能这样:

线程 A 读到 100

线程 B 也读到 100

A 写回 101

B 写回 101

结果本来应该加两次,最后只加了一次。

这就是典型的数据竞争

十、互斥锁 mutex:线程同步的第一核心

互斥锁的作用是:

让同一时刻只有一个线程进入临界区,从而保护共享数据。

1. 互斥锁常用 API

  • pthread_mutex_init

  • pthread_mutex_lock

  • pthread_mutex_unlock

  • pthread_mutex_destroy

2. 典型用法

pthread_mutex_lock(&mutex);/* 临界区:访问共享数据 */pthread_mutex_unlock(&mutex);

3. 什么是临界区?

凡是访问共享资源的那段代码,都可能是临界区。 例如:

  • 修改全局计数器

  • 入队、出队

  • 修改链表

  • 更新状态机

  • 操作共享缓存

4. 加锁的意义不是“卡别人”,而是“保证共享状态正确”

锁的本质目标是正确性。 性能优化一定是在正确性成立之后再做。

十一、互斥锁的常见错误:这是笔试和面试常考点

1. 忘记解锁

结果:其他线程永远阻塞。

2. 锁住太大一段代码

如果你把耗时逻辑放在锁内,比如:

  • 文件写入

  • 网络发送

  • 长时间计算

  • 大量打印

就会导致其他线程长时间等锁,系统吞吐下降。

3. 锁得太小

锁范围不完整,就可能保护不到真正的共享状态。

4. 多把锁顺序不一致

线程 A:先锁 A 再锁 B 线程 B:先锁 B 再锁 A

这种情况非常容易死锁。

5. 在持锁状态下调用可能阻塞很久的函数

例如锁内等待 I/O,风险很大。

十二、死锁:多线程最经典、最头疼的问题之一

1. 什么是死锁?

两个或多个线程互相等待对方持有的资源,导致谁也无法继续。

2. 典型示例

线程 A:

已持有锁 1

等锁 2

线程 B:

已持有锁 2

等锁 1

最终互相卡住。

3. 避免死锁的常用原则

原则一:统一加锁顺序

所有线程都按同样顺序加锁。

原则二:缩短持锁时间

越短越不容易出问题。

原则三:不要在锁内做复杂和阻塞操作

尤其是 I/O。

原则四:必要时使用 trylock 或超时机制

帮助诊断和规避问题。

十三、条件变量 condition variable:从“互斥”升级到“协作”

互斥锁解决的是:

同一时刻只能一个线程访问共享资源。

但很多场景下还需要:

条件不满足时先睡眠,等别人通知我再继续。

这就是条件变量的作用。

1. 条件变量常用 API

  • pthread_cond_init

  • pthread_cond_wait

  • pthread_cond_signal

  • pthread_cond_broadcast

  • pthread_cond_destroy

2. 最核心的函数:pthread_cond_wait

pthread_cond_wait(&cond, &mutex);

这句最关键的语义是:

当前线程释放 mutex

当前线程进入等待

被唤醒后重新竞争 mutex

抢到 mutex 后从 wait 后面继续执行

这是一条必须彻底理解的知识点。

3. 为什么条件变量必须搭配 mutex 使用?

因为等待某个条件本质上是在等“共享状态变化”,而共享状态必须在锁的保护下检查和修改,否则容易:

  • 丢通知

  • 状态不一致

  • 被并发篡改

  • 时序错乱

4. 标准写法:一定要用 while,不要用 if

标准模板:

pthread_mutex_lock(&mutex);while (ready == 0) {    pthread_cond_wait(&cond, &mutex);}
pthread_mutex_unlock(&mutex);  //记得解锁

为什么是 while?

因为:

可能发生虚假唤醒

多线程被唤醒后需要再次检查条件

线程醒来时条件可能已被别的线程改掉

5. signal 与 broadcast 的区别

pthread_cond_signal

唤醒一个等待线程。

pthread_cond_broadcast

唤醒所有等待线程。

6. 应用场景怎么选?

用 signal

当你明确知道:这次变化只够一个线程继续执行。 例如队列里只新增了一个数据。

用 broadcast

当你要让所有等待线程都醒来重新检查条件。 例如程序退出、系统模式切换、初始化完成。

十四、生产者消费者模型:线程协作的经典范式

这是线程模块最重要的工程模型之一。

1. 什么是生产者消费者?

生产者:往共享缓冲区放数据

消费者:从共享缓冲区取数据

配套通常需要:

  • 一个共享队列

  • 一个 mutex

  • not_empty 条件变量

  • not_full 条件变量

2. 为什么这是经典模型?

因为它把“线程间协作”最关键的几个问题都串起来了:

  • 共享数据保护

  • 队列状态管理

  • 条件等待与通知

  • 线程解耦

  • 流水线设计基础

3. 需要掌握哪些点?

队列空了,消费者要等待

队列满了,生产者要等待

入队出队必须在锁保护下完成

修改状态后要发出正确通知

4. 为什么最好用两个条件变量?

因为有两个不同的等待条件:

非空:消费者依赖

非满:生产者依赖

因此通常设计成:

not_empty

not_full

这样语义清晰、逻辑稳定。

十五、信号量 semaphore:另一类常见同步工具

在嵌入式 Linux 线程开发中,信号量也常见。

头文件:

#include <semaphore.h>

1. 信号量的本质

信号量本质上表示“可用资源计数”。

例如:

有多少个可用缓冲区

当前允许几个线程同时进入

有几个任务待处理

2. 常用 API

  • sem_init

  • sem_wait

  • sem_post

  • sem_destroy

3. 与 mutex 的区别

mutex

强调“互斥访问”,一次只能一个线程持有。

semaphore

强调“资源数量”,可以允许多个线程通过,取决于计数值。

4. 常见应用场景

资源池

限流

任务计数

简单同步通知

某些生产者消费者实现

十六、读写锁 rwlock:适合“读多写少”

读写锁的思想是:

多个读线程可以并发进入

写线程必须独占

常用 API:

  • pthread_rwlock_init

  • pthread_rwlock_rdlock

  • pthread_rwlock_wrlock

  • pthread_rwlock_unlock

  • pthread_rwlock_destroy

适用场景:

配置表

查询表

数据字典

读远多于写的共享状态

如果写很多,读写锁不一定有优势。

十七、线程属性:不仅能创建线程,还能控制线程行为

线程属性对象:

pthread_attr_t

常见可配置项

1. 分离状态

joinable

detached

2. 栈大小

非常重要,嵌入式尤其要关注。

3. 调度策略

例如:

SCHED_OTHER

SCHED_FIFO

SCHED_RR

4. 优先级

线程优先级直接影响实时性和调度结果。

十八、线程栈:嵌入式项目里极其容易被忽略

每个线程都有自己的栈。 如果线程里有这些情况,就要特别警惕栈溢出:

大数组放在局部变量里

局部结构体很大

函数调用层次深

递归

同时调用很多库函数

常见建议 建议一

大对象尽量放堆上,不要全放栈里。

建议二

线程栈大小要结合业务评估。

建议三

线程多的时候,默认栈过大也可能浪费内存。

十九、线程取消:会用,但不要滥用

线程取消 API:

pthread_cancel(tid);

它不是“立刻强杀”,而是发出取消请求。 线程是否马上退出,取决于:

取消状态

取消类型

是否到达取消点

为什么说不要滥用?

因为异步取消容易导致:

锁没释放

内存没释放

文件没关闭

状态不一致

工程中更稳妥的方式通常是:

设置退出标志

唤醒阻塞线程

让线程自己清理后退出

这叫优雅退出。

二十、线程局部存储 TLS:每个线程各有一份私有数据

线程局部存储适用于:

每线程上下文

每线程日志标签

每线程错误码

每线程缓存

常用 API:

  • pthread_key_create

  • pthread_setspecific

  • pthread_getspecific

  • pthread_key_delete

优点是: 看起来像全局访问,但实际上每个线程拿到的是自己的数据。

二十一、实时调度与优先级:嵌入式线程必须知道的高级主题

在普通 PC 应用中,大家更关注功能。 在嵌入式 Linux 中,还必须关注调度实时性。

1. 常见调度策略

SCHED_OTHER  普通时间片调度,最常见。

SCHED_FIFO   实时先进先出。

SCHED_RR     实时轮转调度。

2. 为什么优先级重要?

例如:

采集线程不能被低价值线程拖住

日志线程不应该抢占关键控制线程

高优先级线程如果设计不当,可能饿死低优先级线程

3. 优先级反转

经典问题:

低优先级线程持有锁

高优先级线程等待这把锁

中优先级线程不断抢占 CPU

低优先级线程反而得不到机会释放锁

高优先级线程被长期拖住

解决思路:

缩短锁持有时间

使用优先级继承机制

避免高优先级线程依赖长临界区

二十二、CPU 亲和性:多核平台上的重要优化点

线程可以绑定到指定 CPU 核心运行。 常见用途:

减少迁核

提升缓存命中

改善实时性

把关键线程和非关键线程隔离开

多核嵌入式系统中,这一项很有价值。

二十三、阻塞 I/O 与线程退出:工程中非常常见的难点

线程常常阻塞在这些地方:

read

write

recv

accept

select

poll

epoll_wait

pthread_cond_wait

这时如果只是简单设置:

g_stop = 1;

线程往往不会立刻退出,因为它还睡在阻塞点里。

工程中的常见解决办法

使用超时等待

关闭 fd 打断阻塞

用管道/eventfd 唤醒

用条件变量广播

非阻塞 I/O + 轮询

统一事件通知机制

二十四、线程工程设计:真正拉开水平差距的地方

单纯会 pthread_create,还不算会线程。 工程里真正重要的是“怎么组织线程”。

1. 典型线程架构一:流水线模型

例如:

采集线程 → 解析线程 → 处理线程 → 日志线程

优点:

职责清晰

解耦明显

易扩展

易定位问题

2. 典型线程架构二:事件驱动 + 工作线程

主线程负责:

epoll

接收外部事件

分发任务

工作线程负责:

执行业务逻辑

处理任务队列

3. 典型线程架构三:前台实时 + 后台异步

例如:

前台线程:采集、控制、协议收包

后台线程:日志、存盘、上传、统计

这样关键线程不容易被慢操作拖死。

4. 典型线程架构四:看门狗/监控线程

用于:

线程心跳检测

异常监控

队列积压监控

卡死检测

二十五、线程安全设计的核心原则

这部分比单个 API 更重要。

原则一:尽量减少共享

共享越多,同步越复杂,bug 越多。 能通过消息传递解决的,就不要到处共享全局状态。

原则二:共享资源要封装

例如队列应该封装成:

  • queue_init

  • queue_push

  • queue_pop

  • queue_destroy

而不是让所有线程都直接操作:

head

tail

count

lock

cond

原则三:锁内只做最小必要操作

锁内做:

判空

判满

入队

出队

修改共享状态

锁外做:

复杂计算

文件写入

网络发送

printf

耗时业务逻辑

原则四:明确对象所有权

要约定清楚:

谁申请

谁使用

谁释放

否则很容易:

野指针

重复释放

内存泄漏

多线程抢释放

原则五:提前设计退出机制

线程系统最怕的不是“跑不起来”,而是“退不出来”。

二十六、优雅退出:线程工程的分水岭

很多 demo 都写成:

while (1) {    ...}

但真实工程里一定要考虑退出。

一个典型的优雅退出流程

1. 设置全局退出标志

例如:

g_stop = 1;

2. 唤醒所有可能阻塞的线程

例如:

pthread_cond_broadcast

关闭 fd

发事件

写 pipe/eventfd

3. 线程醒来后检测退出标志

满足退出条件就收尾退出。

4. 主线程 join 回收

确保没有线程资源泄漏。

5. 销毁锁、条件变量、队列、fd 等资源

这才叫工程级退出。

二十七、线程调试与排错:这部分决定你能不能真的解决问题

1. 卡死怎么查?

先问自己四个问题:

谁在等谁?

谁拿着锁?

谁阻塞在 I/O?

谁还没退出?

重点排查:

pthread_join

pthread_cond_wait

read/recv/select/poll

多把锁交叉等待

2. CPU 飙高怎么查?

典型原因:

忙等待

死循环

自旋

高频打印

非阻塞轮询写法不合理

3. 数据错乱怎么查?

重点看:

是否访问了共享数据

是否加锁

锁范围是否正确

是否有多个线程同时写同一对象

是否传了无效地址

4. 线程突然崩溃怎么查?

常见原因:

栈溢出

野指针

空指针

重复释放

参数生命周期错误

二十八、线程常见错误清单:复习和笔试特别好用

线程创建成功但没 join 也没 detach

返回局部变量地址

多线程共享同一参数地址

counter++ 未加锁

用 if 包 pthread_cond_wait

修改条件时不加锁

只改标志位,不唤醒等待线程

多个线程等同一 cond 却误以为 signal 会全醒

在锁内做 I/O

锁顺序不一致导致死锁

线程栈设置不合理

退出时没有统一回收机制

多线程同时操作同一个 fd 却没有设计约束

为了快,直接大量用全局变量共享状态

只会写 demo,不会封装队列和模块边界

二十九、嵌入式 Linux 线程模块完整知识树

你可以把线程模块总结成这 8 个大板块:

1. 基础操作

create

join

detach

exit

参数

返回值

2. 共享与竞争

线程共享地址空间

数据竞争

原子性

临界区

3. 同步原语

mutex

cond

semaphore

rwlock

TLS

4. 协作模型

条件等待

signal / broadcast

生产者消费者

队列同步

5. 工程设计

流水线模型

工作线程模型

日志线程

监控线程

退出机制

6. 实时与调度

优先级

调度策略

亲和性

优先级反转

7. 调试排错

死锁

卡死

高 CPU

栈溢出

野指针

8. 性能优化

缩短临界区

减少共享

控制线程数

合理分工

减少不必要上下文切换

三十、笔试题 + 参考答案

下面这部分适合复习、刷题、面试前突击。

笔试题 1 进程和线程的主要区别是什么?

参考答案

    进程是资源分配的基本单位,线程是 CPU 调度的基本单位。 同一进程中的线程共享地址空间、全局变量、堆和文件描述符,但每个线程拥有独立的栈、寄存器上下文和线程 ID。 线程创建和切换开销通常小于进程,但线程间共享资源更多,因此同步问题更突出。

笔试题 2 pthread_create 的作用和四个参数分别是什么?

参考答案

pthread_create 用于创建一个新线程。 四个参数分别是:

返回线程 ID 的指针

线程属性,通常传 NULL

线程入口函数

传递给线程函数的参数**

笔试题 3 为什么线程函数的参数类型和返回值类型都是 void *?

参考答案

    因为线程函数需要支持通用参数和通用返回值。 void * 可以承载任意类型指针,调用者和线程函数通过强制类型转换实现灵活传参和返回结果。

笔试题 4 为什么不能返回局部变量地址?

参考答案

    局部变量位于函数栈帧中,函数返回后生命周期结束,其地址失效。 如果返回局部变量地址,调用方继续访问就会产生未定义行为。

笔试题 5 什么是数据竞争?

参考答案

    多个线程并发访问同一共享数据,并且至少有一个线程执行写操作,同时访问之间没有同步保护,这种情况称为数据竞争。 数据竞争会导致结果不可预测。

笔试题 6 counter++ 为什么不是线程安全的?

参考答案

    因为 counter++ 一般包含读、改、写三个步骤,不是原子操作。 多个线程同时执行时可能发生丢失更新。

笔试题 7 什么是临界区?

参考答案

    访问共享资源的代码区域称为临界区。 为了避免并发访问导致的数据错误,临界区通常需要用互斥锁保护。

笔试题 8 pthread_mutex_lock 和 pthread_mutex_unlock 的作用是什么?

参考答案

pthread_mutex_lock 用于获取互斥锁,进入临界区。 pthread_mutex_unlock 用于释放互斥锁,让其他线程有机会进入临界区。 它们共同用于保护共享数据。

笔试题 9 条件变量的作用是什么?

参考答案

    条件变量用于线程间协作。 当条件不满足时,线程可以在条件变量上等待;当其他线程修改共享状态使条件满足后,通过 signal 或 broadcast 唤醒等待线程。

笔试题 10 为什么 pthread_cond_wait 必须和 mutex 一起使用?

参考答案

    因为线程等待的“条件”本质上依赖共享状态,而共享状态必须在锁保护下检查和修改。 pthread_cond_wait 会原子地释放 mutex 并进入等待,被唤醒后再重新获取 mutex,从而保证条件检查和等待之间不会出现竞态。

笔试题 11 为什么等待条件变量时要用 while 而不是 if?

参考答案

    因为线程可能被虚假唤醒,也可能被唤醒后发现条件已经被其他线程改变。 因此线程醒来后必须再次检查条件,所以标准写法是 while。

笔试题 12 pthread_cond_signal 和 pthread_cond_broadcast 有什么区别?

参考答案

pthread_cond_signal 唤醒一个等待线程。                 pthread_cond_broadcast 唤醒所有等待线程。 通常当一次状态变化只够一个线程继续时用 signal, 当所有线程都需要重新检查条件用broadcast。

笔试题 13 什么是死锁?如何避免?

参考答案

死锁是指多个线程互相等待对方占有的资源,导致无法继续执行。 避免方法包括:

统一加锁顺序

缩短持锁时间

避免锁内阻塞操作

减少多锁嵌套

笔试题 14 什么是优先级反转?

参考答案

    高优先级线程等待低优先级线程持有的锁,而中优先级线程不断运行,导致低优先级线程无法及时释放锁,从而让高优先级线程被间接阻塞,这种现象叫优先级反转。

笔试题 15 什么是优雅退出?

参考答案

    优雅退出是指线程在接收到退出请求后,不是立即被暴力结束,而是按照约定流程:

设置退出标志

唤醒阻塞线程

完成必要清理

正常退出

被主线程回收

从而保证资源一致性和系统稳定性。

三十一、面试题 + 参考答案

面试题 1 在嵌入式 Linux 开发中,什么时候适合用线程,什么时候更适合用进程?

参考答案

    当多个任务需要高效共享数据、切换开销要尽量小、协作非常频繁时,更适合用线程。 当系统需要更强的故障隔离、模块独立部署、崩溃影响要可控时,更适合用进程。 嵌入式系统中,很多应用层采集、处理、日志、通信模块常用线程实现;而对安全隔离要求更高的服务拆分常用进程方案。

面试题 2 你在项目里是怎么设计线程模型的?

参考答案

    我通常不会让多个线程直接共享大量全局变量,而是按职责划分线程,例如采集线程、处理线程、日志线程,通过线程安全队列传递数据。 共享队列内部封装 mutex 和条件变量,线程之间以消息或数据块传递为主。 同时会设计统一的退出机制,包括停止标志、阻塞唤醒和 join 回收,确保线程系统可控可维护。

面试题 3 讲一下你对 mutex 和 cond 的理解。

参考答案

    mutex 解决的是互斥问题,保证同一时刻只有一个线程访问共享状态。 cond 解决的是协作问题,当条件不满足时线程睡眠等待,条件满足后由其他线程通知。 两者经常配合使用:mutex 保护共享条件,cond 实现等待和唤醒。 使用时要遵循“加锁、while 检查条件、wait、条件满足继续执行”的模板。

面试题 4 为什么修改条件后一般要先改状态,再发 signal?

参考答案

    因为线程等待的是“共享状态变化后的条件成立”,所以应该先在锁保护下修改共享状态,再通知等待线程。 这样被唤醒的线程醒来后重新检查条件时,才能看到一致的已更新状态。

面试题 5 多个线程等待同一个条件变量时,能否指定唤醒某一个固定线程?

参考答案

    使用同一个条件变量调用 pthread_cond_signal 时,只能唤醒其中一个等待线程,但具体是哪一个线程通常不可控。 如果业务上需要定向唤醒某个指定线程,更合理的设计是:

每个线程拥有独立条件变量

或每个线程拥有自己的任务队列

或通过事件分发机制实现定向通知

面试题 6 线程为什么会卡死?你怎么排查?

参考答案

线程卡死通常有几类原因:

死锁

阻塞在 cond wait 或 I/O

主线程 join 等待未退出线程

退出标志设置了但没有唤醒阻塞线程

    排查时我会先定位线程状态,看它阻塞在哪个调用点;再看锁持有情况、条件变量等待条件、I/O 状态和退出流程。 如果有日志,我会重点看锁前锁后、入队出队、等待唤醒、退出路径。

面试题 7 生产者消费者模型在工程里有什么意义?

参考答案

    生产者消费者模型本质上是一种线程解耦机制。 它将数据产生和数据处理分开,通过线程安全队列连接,既能提升模块边界清晰度,也能降低直接共享状态带来的复杂度。 在嵌入式项目中,串口收包与协议解析、传感器采集与算法处理、业务处理与日志落盘都适合这种模型。

面试题 8 高优先级线程为什么不应该在锁内做耗时操作?

参考答案

    高优先级线程如果长时间持锁,会导致其他线程无法进入临界区,放大系统阻塞范围。 如果它在锁内做文件写入、网络发送、复杂计算等耗时操作,还会进一步影响系统实时性,甚至引发优先级反转和响应抖动。 所以高优先级线程应尽量缩短临界区,只在锁内完成共享状态最小修改。

面试题 9 线程退出时你最关注什么?

参考答案

我最关注三件事:

第一,线程是否可能阻塞在 wait 或 I/O。 第二,退出时是否能被可靠唤醒。 第三,资源是否能被一致性回收。

我通常会设计停止标志、唤醒机制、线程回收流程和资源销毁顺序,避免出现线程没退干净、锁没释放、fd 没关闭、对象重复释放等问题。

面试题 10 嵌入式 Linux 线程开发中,你认为最容易被忽略的问题是什么?

参考答案

我认为最容易被忽略的是:

线程栈大小

退出机制

锁内耗时操作

参数生命周期

多线程共享 fd 的使用规则

很多程序能跑起来,但在长时间运行、异常退出、高负载或者边界条件下出问题,根源往往就在这些细节。

三十二、编程题

下面给你一组从基础到工程的线程编程题。 这些题很适合练习、笔试、面试上机和项目复盘。

编程题 1:创建一个线程并等待它结束

题目要求

编写一个程序,创建一个子线程,子线程打印 "hello thread",主线程等待其结束后打印 "main exit"。

考察点

pthread_create

线程函数格式

pthread_join

编程题 2:创建 5 个线程,给每个线程传不同的编号

题目要求

创建 5 个线程,每个线程打印自己的线程编号和 pthread ID。

考察点

多线程创建

参数传递

循环变量地址问题

提示

不要直接把循环变量 i 的地址传进去。

编程题 3:线程返回计算结

题目要求

创建一个线程,计算 1 到 100 的和,并将结果返回给主线程打印。

考察点

线程返回值

pthread_join

堆内存返回结果

编程题 4:两个线程同时累加全局计数器

题目要求

两个线程分别将全局变量 counter 累加 100000 次。 先写一个未加锁版本,再写一个加锁版本,比较结果。

考察点

数据竞争

counter++ 非线程安全

mutex 的使用

编程题 5:一个线程等待,主线程唤醒

题目要求

子线程在 ready == 0 时等待;主线程 3 秒后设置 ready = 1 并唤醒子线程。

考察点

条件变量

pthread_cond_wait

while 检查条件

signal 通知

编程题 6:两个线程同时等待,比较 signal 与 broadcast

题目要求

创建两个子线程,它们都在等待同一个条件变量。 主线程分别测试:

用 pthread_cond_signal

用 pthread_cond_broadcast

观察输出差异。

考察点

多线程等待同一条件变量

signal 与 broadcast 的区别

编程题 7:实现一个固定长度的生产者消费者模型

题目要求

使用一个长度为 5 的环形缓冲区,实现:

一个生产者线程

一个消费者线程

生产者生产 10 个整数,消费者消费 10 个整数。

考察点

环形队列

mutex

条件变量

not_empty

not_full

编程题 8:给生产者消费者增加退出机制

题目要求

在上一题基础上增加 done 或 stop 标志。 当生产者生产完毕后,消费者不能永久卡在等待状态,而是能够正常退出。

考察点

优雅退出

broadcast

阻塞线程退出条件设计

编程题 9:三线程流水线模型

题目要求

设计三个线程:

采集线程:每 200ms 产生一个整数

处理线程:将数据乘 10

日志线程:输出处理结果

线程之间通过两个线程安全队列连接。

考察点

工程化线程设计

数据流解耦

多级生产者消费者

退出机制

编程题 10:日志线程异步化

题目要求

主线程不断产生日志消息,日志线程负责异步写文件。 要求主线程不能因为文件 I/O 被严重阻塞。

考察点

异步日志思想

队列缓冲

锁粒度

I/O 与业务解耦

编程题 11:多线程访问共享配置,使用读写锁

题目要求

多个读线程频繁读取配置,一个写线程偶尔更新配置。 要求设计读写锁保护。

考察点

pthread_rwlock

读多写少场景建模

编程题 12:设计一个支持优雅退出的阻塞收包线程

题目要求

设计一个网络接收线程,它会阻塞在 recv 或 select 上。 要求程序退出时,该线程能够被唤醒并正常退出。

考察点

阻塞 I/O

停止标志

唤醒机制

工程级退出设计

三十三、附:适合项目实战的线程学习路线

如果你想把线程真正学到“能做项目”的程度,我建议按下面顺序推进:

第一阶段:基础必会

创建线程

join / detach

参数传递

返回值

多线程并发现象

第二阶段:同步必会

共享变量

数据竞争

mutex

死锁

锁粒度

第三阶段:协作必会

条件变量

signal / broadcast

生产者消费者

退出机制

第四阶段:工程必会

线程安全队列

三线程流水线

异步日志

阻塞 I/O 退出

监控线程

第五阶段:进阶必会

信号量

读写锁

TLS

优先级

调度策略

CPU 亲和性

性能优化与排错

三十四、全文总结:把线程真正学明白,就抓住这 10 句话

  1. 线程共享地址空间,通信方便,但同步复杂。

  2. 线程问题的根源,往往不是函数不会写,而是时序不可预测。

  3. 只要有共享写,就必须考虑同步。

  4. mutex 解决互斥,cond 解决协作。

  5. pthread_cond_wait 的本质是:释放锁、睡眠、被唤醒后重新加锁。

  6. 等待条件变量必须用 while,而不是 if。

  7. signal 适合唤醒一个,broadcast 适合唤醒全部。

  8. 线程工程化的关键,不是更多全局变量,而是更少共享、更清晰边界。

  9. 退出机制必须事先设计,否则线程系统迟早卡死。

  10. 真正的线程高手,不仅会写代码,更会设计、排错和收尾。

最新文章

随机文章

基本 文件 流程 错误 SQL 调试
  1. 请求信息 : 2026-03-27 16:36:27 HTTP/2.0 GET : https://f.mffb.com.cn/a/480449.html
  2. 运行时间 : 0.110513s [ 吞吐率:9.05req/s ] 内存消耗:4,817.82kb 文件加载:140
  3. 缓存信息 : 0 reads,0 writes
  4. 会话信息 : SESSION_ID=80bdb5bc2bd14f6f44353377bea5aebf
  1. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/public/index.php ( 0.79 KB )
  2. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/autoload.php ( 0.17 KB )
  3. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/autoload_real.php ( 2.49 KB )
  4. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/platform_check.php ( 0.90 KB )
  5. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/ClassLoader.php ( 14.03 KB )
  6. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/autoload_static.php ( 4.90 KB )
  7. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper.php ( 8.34 KB )
  8. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-validate/src/helper.php ( 2.19 KB )
  9. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/helper.php ( 1.47 KB )
  10. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/stubs/load_stubs.php ( 0.16 KB )
  11. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Exception.php ( 1.69 KB )
  12. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-container/src/Facade.php ( 2.71 KB )
  13. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/deprecation-contracts/function.php ( 0.99 KB )
  14. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/polyfill-mbstring/bootstrap.php ( 8.26 KB )
  15. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/polyfill-mbstring/bootstrap80.php ( 9.78 KB )
  16. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/var-dumper/Resources/functions/dump.php ( 1.49 KB )
  17. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-dumper/src/helper.php ( 0.18 KB )
  18. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/var-dumper/VarDumper.php ( 4.30 KB )
  19. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/App.php ( 15.30 KB )
  20. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-container/src/Container.php ( 15.76 KB )
  21. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/container/src/ContainerInterface.php ( 1.02 KB )
  22. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/provider.php ( 0.19 KB )
  23. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Http.php ( 6.04 KB )
  24. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper/Str.php ( 7.29 KB )
  25. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Env.php ( 4.68 KB )
  26. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/common.php ( 0.03 KB )
  27. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/helper.php ( 18.78 KB )
  28. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Config.php ( 5.54 KB )
  29. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/app.php ( 0.95 KB )
  30. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/cache.php ( 0.78 KB )
  31. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/console.php ( 0.23 KB )
  32. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/cookie.php ( 0.56 KB )
  33. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/database.php ( 2.48 KB )
  34. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/Env.php ( 1.67 KB )
  35. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/filesystem.php ( 0.61 KB )
  36. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/lang.php ( 0.91 KB )
  37. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/log.php ( 1.35 KB )
  38. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/middleware.php ( 0.19 KB )
  39. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/route.php ( 1.89 KB )
  40. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/session.php ( 0.57 KB )
  41. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/trace.php ( 0.34 KB )
  42. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/view.php ( 0.82 KB )
  43. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/event.php ( 0.25 KB )
  44. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Event.php ( 7.67 KB )
  45. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/service.php ( 0.13 KB )
  46. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/AppService.php ( 0.26 KB )
  47. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Service.php ( 1.64 KB )
  48. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Lang.php ( 7.35 KB )
  49. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/lang/zh-cn.php ( 13.70 KB )
  50. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/Error.php ( 3.31 KB )
  51. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/RegisterService.php ( 1.33 KB )
  52. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/services.php ( 0.14 KB )
  53. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/PaginatorService.php ( 1.52 KB )
  54. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/ValidateService.php ( 0.99 KB )
  55. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/ModelService.php ( 2.04 KB )
  56. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/Service.php ( 0.77 KB )
  57. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Middleware.php ( 6.72 KB )
  58. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/BootService.php ( 0.77 KB )
  59. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/Paginator.php ( 11.86 KB )
  60. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-validate/src/Validate.php ( 63.20 KB )
  61. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/Model.php ( 23.55 KB )
  62. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/Attribute.php ( 21.05 KB )
  63. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/AutoWriteData.php ( 4.21 KB )
  64. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/Conversion.php ( 6.44 KB )
  65. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/DbConnect.php ( 5.16 KB )
  66. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/ModelEvent.php ( 2.33 KB )
  67. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/RelationShip.php ( 28.29 KB )
  68. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/contract/Arrayable.php ( 0.09 KB )
  69. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/contract/Jsonable.php ( 0.13 KB )
  70. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/contract/Modelable.php ( 0.09 KB )
  71. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Db.php ( 2.88 KB )
  72. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/DbManager.php ( 8.52 KB )
  73. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Log.php ( 6.28 KB )
  74. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Manager.php ( 3.92 KB )
  75. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/log/src/LoggerTrait.php ( 2.69 KB )
  76. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/log/src/LoggerInterface.php ( 2.71 KB )
  77. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Cache.php ( 4.92 KB )
  78. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/simple-cache/src/CacheInterface.php ( 4.71 KB )
  79. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper/Arr.php ( 16.63 KB )
  80. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/cache/driver/File.php ( 7.84 KB )
  81. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/cache/Driver.php ( 9.03 KB )
  82. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/CacheHandlerInterface.php ( 1.99 KB )
  83. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/Request.php ( 0.09 KB )
  84. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Request.php ( 55.78 KB )
  85. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/middleware.php ( 0.25 KB )
  86. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Pipeline.php ( 2.61 KB )
  87. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/TraceDebug.php ( 3.40 KB )
  88. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/middleware/SessionInit.php ( 1.94 KB )
  89. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Session.php ( 1.80 KB )
  90. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/session/driver/File.php ( 6.27 KB )
  91. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/SessionHandlerInterface.php ( 0.87 KB )
  92. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/session/Store.php ( 7.12 KB )
  93. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Route.php ( 23.73 KB )
  94. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleName.php ( 5.75 KB )
  95. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Domain.php ( 2.53 KB )
  96. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleGroup.php ( 22.43 KB )
  97. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Rule.php ( 26.95 KB )
  98. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleItem.php ( 9.78 KB )
  99. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/route/app.php ( 1.72 KB )
  100. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/Route.php ( 4.70 KB )
  101. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/dispatch/Controller.php ( 4.74 KB )
  102. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Dispatch.php ( 10.44 KB )
  103. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/controller/Index.php ( 4.81 KB )
  104. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/BaseController.php ( 2.05 KB )
  105. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/facade/Db.php ( 0.93 KB )
  106. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/connector/Mysql.php ( 5.44 KB )
  107. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/PDOConnection.php ( 52.47 KB )
  108. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Connection.php ( 8.39 KB )
  109. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/ConnectionInterface.php ( 4.57 KB )
  110. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/builder/Mysql.php ( 16.58 KB )
  111. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Builder.php ( 24.06 KB )
  112. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/BaseBuilder.php ( 27.50 KB )
  113. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Query.php ( 15.71 KB )
  114. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/BaseQuery.php ( 45.13 KB )
  115. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/TimeFieldQuery.php ( 7.43 KB )
  116. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/AggregateQuery.php ( 3.26 KB )
  117. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ModelRelationQuery.php ( 20.07 KB )
  118. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ParamsBind.php ( 3.66 KB )
  119. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ResultOperation.php ( 7.01 KB )
  120. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/WhereQuery.php ( 19.37 KB )
  121. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/JoinAndViewQuery.php ( 7.11 KB )
  122. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/TableFieldInfo.php ( 2.63 KB )
  123. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/Transaction.php ( 2.77 KB )
  124. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/log/driver/File.php ( 5.96 KB )
  125. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/LogHandlerInterface.php ( 0.86 KB )
  126. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/log/Channel.php ( 3.89 KB )
  127. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/event/LogRecord.php ( 1.02 KB )
  128. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/Collection.php ( 16.47 KB )
  129. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/View.php ( 1.70 KB )
  130. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/View.php ( 4.39 KB )
  131. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Response.php ( 8.81 KB )
  132. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/response/View.php ( 3.29 KB )
  133. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Cookie.php ( 6.06 KB )
  134. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-view/src/Think.php ( 8.38 KB )
  135. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/TemplateHandlerInterface.php ( 1.60 KB )
  136. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/Template.php ( 46.61 KB )
  137. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/template/driver/File.php ( 2.41 KB )
  138. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/template/contract/DriverInterface.php ( 0.86 KB )
  139. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/runtime/temp/067d451b9a0c665040f3f1bdd3293d68.php ( 11.98 KB )
  140. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/Html.php ( 4.42 KB )
  1. CONNECT:[ UseTime:0.000925s ] mysql:host=127.0.0.1;port=3306;dbname=f_mffb;charset=utf8mb4
  2. SHOW FULL COLUMNS FROM `fenlei` [ RunTime:0.001593s ]
  3. SELECT * FROM `fenlei` WHERE `fid` = 0 [ RunTime:0.000758s ]
  4. SELECT * FROM `fenlei` WHERE `fid` = 63 [ RunTime:0.000926s ]
  5. SHOW FULL COLUMNS FROM `set` [ RunTime:0.001594s ]
  6. SELECT * FROM `set` [ RunTime:0.000675s ]
  7. SHOW FULL COLUMNS FROM `article` [ RunTime:0.001550s ]
  8. SELECT * FROM `article` WHERE `id` = 480449 LIMIT 1 [ RunTime:0.002063s ]
  9. UPDATE `article` SET `lasttime` = 1774600587 WHERE `id` = 480449 [ RunTime:0.006730s ]
  10. SELECT * FROM `fenlei` WHERE `id` = 67 LIMIT 1 [ RunTime:0.000613s ]
  11. SELECT * FROM `article` WHERE `id` < 480449 ORDER BY `id` DESC LIMIT 1 [ RunTime:0.001299s ]
  12. SELECT * FROM `article` WHERE `id` > 480449 ORDER BY `id` ASC LIMIT 1 [ RunTime:0.001107s ]
  13. SELECT * FROM `article` WHERE `id` < 480449 ORDER BY `id` DESC LIMIT 10 [ RunTime:0.001905s ]
  14. SELECT * FROM `article` WHERE `id` < 480449 ORDER BY `id` DESC LIMIT 10,10 [ RunTime:0.002940s ]
  15. SELECT * FROM `article` WHERE `id` < 480449 ORDER BY `id` DESC LIMIT 20,10 [ RunTime:0.004356s ]
0.112159s