当前位置:首页>Linux>Linux 内核死锁问题诊断与解决

Linux 内核死锁问题诊断与解决

  • 2026-03-27 10:08:56
Linux 内核死锁问题诊断与解决

从理论到实战,彻底掌握死锁的检测、分析和预防


📋 目录速览


🎯 什么是死锁

定义

死锁(Deadlock)是指两个或多个进程(或线程)在执行过程中,因争夺资源而造成的一种互相等待的现象。若无外力作用,这些进程都将无法继续执行。

死锁示意图

内核中的死锁

死锁 vs 其他问题

问题类型特征CPU 使用率可恢复性检测方式
死锁互相等待资源低或正常通常不可恢复lockdep, hung task
活锁不断重试但无进展可能自行恢复CPU profiling
饥饿长期得不到资源可能恢复调度分析
忙等待自旋等待100%可能超时perf, ftrace

📐 死锁的四个必要条件

死锁的发生必须同时满足以下四个条件(Coffman 条件):

1. 互斥条件(Mutual Exclusion)

示例

spinlock_t my_lock;
// 进程 A
spin_lock(&my_lock);    // 获取锁
// 临界区
spin_unlock(&my_lock);
// 进程 B
spin_lock(&my_lock);    // 等待进程 A 释放

2. 持有并等待(Hold and Wait)

示例

// 进程 A
spin_lock(&lock_x);     // 持有 lock_x
spin_lock(&lock_y);     // 等待 lock_y
// 进程 B
spin_lock(&lock_y);     // 持有 lock_y
spin_lock(&lock_x);     // 等待 lock_x

3. 不可剥夺(No Preemption)

4. 循环等待(Circular Wait)

示例

// 进程 A
spin_lock(&lock_a);
spin_lock(&lock_b);  // 等待 B 释放
// 进程 B
spin_lock(&lock_b);
spin_lock(&lock_c);  // 等待 C 释放
// 进程 C
spin_lock(&lock_c);
spin_lock(&lock_a);  // 等待 A 释放
// 形成循环:A → B → C → A

破坏死锁条件


🔍 死锁的类型

1. 自死锁(Self-Deadlock)

进程尝试获取自己已经持有的锁。

// 错误示例
spin_lock(&my_lock);
// ... 一些代码 ...
spin_lock(&my_lock);  // 死锁!自己等待自己

检测

lockdep 会立即检测到:
"BUG: spinlock recursion on CPU#0"

修复

// 方法 1:避免重复加锁
spin_lock(&my_lock);
// ... 所有需要保护的代码 ...
spin_unlock(&my_lock);
// 方法 2:使用递归锁(如果必要)
// 注意:内核自旋锁不支持递归,互斥锁可以

2. AB-BA 死锁

两个进程以相反的顺序获取两个锁。

// 进程 A
void function_a(void) {
spin_lock(&lock_a);
spin_lock(&lock_b);  // 等待 B 释放 lock_b
// ...
spin_unlock(&lock_b);
spin_unlock(&lock_a);
}
// 进程 B
void function_b(void) {
spin_lock(&lock_b);
spin_lock(&lock_a);  // 等待 A 释放 lock_a
// ...
spin_unlock(&lock_a);
spin_unlock(&lock_b);
}

死锁场景

时间线:
T1: 进程 A 获取 lock_a
T2: 进程 B 获取 lock_b
T3: 进程 A 等待 lock_b (被 B 持有)
T4: 进程 B 等待 lock_a (被 A 持有)
→ 死锁!

修复

// 统一锁顺序:总是先获取 lock_a,再获取 lock_b
void function_a(void) {
spin_lock(&lock_a);
spin_lock(&lock_b);
// ...
spin_unlock(&lock_b);
spin_unlock(&lock_a);
}
void function_b(void) {
spin_lock(&lock_a);  // 改为先获取 lock_a
spin_lock(&lock_b);
// ...
spin_unlock(&lock_b);
spin_unlock(&lock_a);
}

3. 循环死锁(Circular Deadlock)

多个进程形成循环等待链。

// 进程 A
spin_lock(&lock_a);
spin_lock(&lock_b);
// 进程 B
spin_lock(&lock_b);
spin_lock(&lock_c);
// 进程 C
spin_lock(&lock_c);
spin_lock(&lock_a);
// 循环:A → B → C → A

死锁图

修复

// 定义全局锁顺序:lock_a < lock_b < lock_c
// 所有进程都按此顺序获取
// 进程 A
spin_lock(&lock_a);
spin_lock(&lock_b);
// 进程 B
spin_lock(&lock_b);
spin_lock(&lock_c);
// 进程 C
spin_lock(&lock_a);  // 改为按顺序
spin_lock(&lock_c);

4. 中断上下文死锁

进程上下文和中断上下文之间的死锁。

// 进程上下文
void process_function(void) {
spin_lock(&my_lock);
// ... 临界区 ...
// 此时中断发生!
spin_unlock(&my_lock);
}
// 中断处理程序
void interrupt_handler(void) {
spin_lock(&my_lock);  // 死锁!等待进程上下文释放
// ...
spin_unlock(&my_lock);
}

修复

// 使用 spin_lock_irqsave 禁用中断
void process_function(void) {
unsigned long flags;
spin_lock_irqsave(&my_lockflags);
// ... 临界区(中断被禁用)...
spin_unlock_irqrestore(&my_lockflags);
}
// 中断处理程序
void interrupt_handler(void) {
spin_lock(&my_lock);  // 安全:进程上下文已禁用中断
// ...
spin_unlock(&my_lock);
}

5. 读写锁死锁

读写锁使用不当导致的死锁。

// 错误:写者等待读者,读者等待写者
void reader_function(void) {
read_lock(&rw_lock);
// ... 读操作 ...
write_lock(&rw_lock);  // 死锁!读者尝试升级为写者
// ...
}
void writer_function(void) {
write_lock(&rw_lock);  // 等待读者释放
// ...
}

修复

// 方法 1:避免锁升级
void reader_function(void) {
read_lock(&rw_lock);
// ... 只读操作 ...
read_unlock(&rw_lock);
}
// 方法 2:使用写锁
void reader_writer_function(void) {
write_lock(&rw_lock);  // 直接使用写锁
// ... 读写操作 ...
write_unlock(&rw_lock);
}

🛡️ 内核死锁检测机制

Linux 内核提供了多种死锁检测机制:

1. lockdep(Lock Dependency Validator)

最强大的死锁检测工具,可以在运行时检测潜在的死锁。

启用 lockdep

# 内核配置
CONFIG_PROVE_LOCKING=y
CONFIG_LOCK_STAT=y
CONFIG_DEBUG_LOCK_ALLOC=y
CONFIG_DEBUG_LOCKDEP=y
# 运行时检查
cat /proc/lockdep
cat /proc/lockdep_stats

2. Hung Task 检测

检测长时间处于 D 状态(不可中断睡眠)的进程。

# 配置
CONFIG_DETECT_HUNG_TASK=y
# 参数设置
sysctl -w kernel.hung_task_timeout_secs=120# 120秒超时
sysctl -w kernel.hung_task_warnings=10# 最多10个警告
sysctl -w kernel.hung_task_panic=0# 不触发 panic

检测输出

3. Soft Lockup 检测

检测 CPU 长时间不响应(通常是自旋锁持有时间过长)。

# 配置
CONFIG_SOFTLOCKUP_DETECTOR=y
# 参数设置
sysctl -w kernel.soft_watchdog=1
sysctl -w kernel.watchdog_thresh=10# 10秒阈值

检测输出

4. Hard Lockup 检测

检测 CPU 完全无响应(中断被长时间禁用)。

# 配置
CONFIG_HARDLOCKUP_DETECTOR=y
# 参数设置
sysctl -w kernel.nmi_watchdog=1

5. RCU Stall 检测

检测 RCU 读临界区持有时间过长。


🔬 lockdep 死锁检测器

lockdep 原理

lockdep 通过记录锁的依赖关系来检测潜在的死锁:

lockdep 报告解读

典型 lockdep 报告

报告字段解读

1. 锁状态标记

2. 依赖链

-> #1 (&lock_a)  ← 第一个锁
-> #0 (&lock_b)  ← 第二个锁(当前尝试获取)
依赖关系:lock_a → lock_b

3. 死锁场景

lockdep 统计信息

# 查看 lockdep 统计
cat /proc/lockdep_stats
 lock-classes:                     1234 [max: 8192]
 direct dependencies:              5678 [max: 32768]
 indirect dependencies:           12345
 all direct dependencies:         23456
 dependency chains:                3456 [max: 65536]
 dependency chain hlocks:         12345 [max: 327680]
 in-hardirq chains:                 123
 in-softirq chains:                 456
 in-process chains:                2877
 stack-trace entries:             45678 [max: 524288]
 combined max dependencies:    12345678
 hardirq-safe locks:                 12
 hardirq-unsafe locks:              234
 softirq-safe locks:                 34
 softirq-unsafe locks:              456
 irq-safe locks:                     56
 irq-unsafe locks:                  678

lockdep 类型

1. 自旋锁(Spinlock)

spinlock_t my_lock;
spin_lock(&my_lock);
// 临界区
spin_unlock(&my_lock);
// 禁用中断版本
unsigned long flags;
spin_lock_irqsave(&my_lockflags);
// 临界区
spin_unlock_irqrestore(&my_lockflags);

2. 互斥锁(Mutex)

struct mutex my_mutex;
mutex_lock(&my_mutex);
// 临界区(可睡眠)
mutex_unlock(&my_mutex);
// 可中断版本
if (mutex_lock_interruptible(&my_mutex))
return -EINTR;

3. 读写锁(RW Lock)

rwlock_t my_rwlock;
// 读锁
read_lock(&my_rwlock);
// 读操作
read_unlock(&my_rwlock);
// 写锁
write_lock(&my_rwlock);
// 写操作
write_unlock(&my_rwlock);

4. 信号量(Semaphore)

struct semaphore my_sem;
down(&my_sem);
// 临界区
up(&my_sem);
// 可中断版本
if (down_interruptible(&my_sem))
return -EINTR;

📖 死锁信息解读

1. Hung Task 报告

解读

  • 进程名:kworker/0:1

  • PID:123

  • 状态:D(不可中断睡眠)

  • 阻塞时间:120 秒

  • 等待点:wait_for_completion(等待完成)

  • 调用路径:ioctl → flush_work → wait_for_completion

2. Soft Lockup 报告

解读

  • CPU:2 号 CPU

  • 卡住时间:22 秒

  • 当前位置:_raw_spin_lock(正在尝试获取自旋锁)

  • 问题:自旋锁持有时间过长或死锁

3. 查看进程状态

# 查看所有 D 状态进程
ps aux | awk'$8 == "D"'
# 查看进程调用栈
cat /proc/<pid>/stack
# 查看进程持有的锁
cat /proc/<pid>/locks
# 查看所有锁
cat /proc/locks

🔍 常见死锁场景

场景 1:文件系统死锁

问题代码

// 进程 A:写文件
void write_file(void) {
mutex_lock(&inode->i_mutex);
// 写操作需要分配内存
buffer=kmalloc(sizeGFP_KERNEL);
// 内存不足,触发回收
// 回收需要写回脏页
// 写回需要获取 i_mutex
// 死锁!
}

死锁链

进程 A: 持有 i_mutex → 等待内存
内存回收: 需要写回 → 等待 i_mutex

解决方案

// 使用 GFP_NOFS 避免文件系统递归
void write_file(void) {
mutex_lock(&inode->i_mutex);
// 使用 GFP_NOFS 防止回收触发文件系统操作
buffer=kmalloc(sizeGFP_NOFS);
// ...
mutex_unlock(&inode->i_mutex);
}

场景 2:网络子系统死锁

问题代码

// 发送路径
void send_packet(struct sk_buff *skb) {
spin_lock(&dev->tx_lock);
// 发送队列满,等待
wait_event(dev->tx_queue_emptyqueue_has_space());
// 死锁!在持有自旋锁时睡眠
}
// 接收路径(中断)
void receive_packet(void) {
spin_lock(&dev->tx_lock);  // 等待发送路径释放
// 处理接收
wake_up(&dev->tx_queue_empty);
}

解决方案

// 方法 1:不在持有自旋锁时睡眠
void send_packet(struct sk_buff *skb) {
// 先检查队列
if (!queue_has_space()) {
wait_event(dev->tx_queue_emptyqueue_has_space());
    }
spin_lock(&dev->tx_lock);
// 发送
spin_unlock(&dev->tx_lock);
}
// 方法 2:使用不同的锁
void send_packet(struct sk_buff *skb) {
mutex_lock(&dev->tx_mutex);  // 使用互斥锁
wait_event(dev->tx_queue_emptyqueue_has_space());
// 发送
mutex_unlock(&dev->tx_mutex);
}

场景 3:内存管理死锁

问题代码

// 进程 A
void allocate_memory(void) {
spin_lock(&zone->lock);
page=alloc_page(GFP_KERNEL);  // 可能触发回收
// 回收需要获取 zone->lock
// 死锁!
}

解决方案

// 使用 GFP_ATOMIC 避免回收
void allocate_memory(void) {
spin_lock(&zone->lock);
page=alloc_page(GFP_ATOMIC);  // 不触发回收
spin_unlock(&zone->lock);
if (!page) {
// 在锁外重试
page=alloc_page(GFP_KERNEL);
    }
}

场景 4:设备驱动死锁

问题代码

// 用户空间调用
static long device_ioctl(struct file *fileunsigned int cmd
unsigned long arg) {
mutex_lock(&dev->mutex);
switch (cmd) {
case IOCTL_RESET:
// 重置设备,等待中断
wait_for_completion(&dev->reset_done);
break;
    }
mutex_unlock(&dev->mutex);
return 0;
}
// 中断处理
static irqreturn_t device_interrupt(int irqvoid *data) {
struct device *dev=data;
mutex_lock(&dev->mutex);  // 等待 ioctl 释放
complete(&dev->reset_done);
mutex_unlock(&dev->mutex);
return IRQ_HANDLED;
}

死锁链

ioctl: 持有 mutex → 等待 completion
中断: 需要 mutex → 无法 complete

解决方案

// 方法 1:中断处理不加锁
static irqreturn_t device_interrupt(int irqvoid *data) {
struct device *dev=data;
// 不加锁,直接 complete
complete(&dev->reset_done);
return IRQ_HANDLED;
}
// 方法 2:使用自旋锁
static long device_ioctl(struct file *fileunsigned int cmd
unsigned long arg) {
unsigned long flags;
spin_lock_irqsave(&dev->lockflags);
// 设置标志
dev->reset_requested=true;
spin_unlock_irqrestore(&dev->lockflags);
// 在锁外等待
wait_for_completion(&dev->reset_done);
return0;
}

🛠️ 调试工具与方法

1. 使用 lockdep

# 启用 lockdep
echo1 > /proc/sys/kernel/lock_stat
# 查看锁统计
cat /proc/lock_stat
# 查看锁依赖
cat /proc/lockdep
# 查看锁依赖链
cat /proc/lockdep_chains

2. 使用 perf lock

3. 使用 ftrace

# 启用函数跟踪
echo function_graph > /sys/kernel/debug/tracing/current_tracer
# 设置过滤器
echo'*lock*' > /sys/kernel/debug/tracing/set_ftrace_filter
# 开始跟踪
echo1 > /sys/kernel/debug/tracing/tracing_on
# 查看结果
cat /sys/kernel/debug/tracing/trace

4. 使用 SystemTap

5. 使用 eBPF/bpftrace

6. 手动分析


📚 实战案例分析

案例 1:文件系统 AB-BA 死锁

问题描述

系统在高负载下出现大量进程处于 D 状态,无法响应。

死锁报告

分析过程

  1. 识别死锁类型:从 lockdep 报告可以看出,这是一个 AB-BA 死锁

    • 进程 A:持有 inode1 的锁,尝试获取 inode2 的锁

    • 进程 B:持有 inode2 的锁,尝试获取 inode1 的锁

  2. 查看调用栈

# 查看进程 A 的调用栈
cat /proc/1234/stack
[<0>] inode_lock+0x1e/0x30
[<0>] vfs_rename+0x123/0x456
[<0>] do_renameat2+0x4a3/0x5e0
[<0>] __x64_sys_renameat2+0x4b/0x60
[<0>] do_syscall_64+0x33/0x40
[<0>] entry_SYSCALL_64_after_hwframe+0x44/0xa9
# 查看进程 B 的调用栈
cat /proc/5678/stack
[<0>] inode_lock+0x1e/0x30
[<0>] vfs_unlink+0x5e/0x1a0
[<0>] do_unlinkat+0x1a3/0x2e0
[<0>] __x64_sys_unlinkat+0x3f/0x50
[<0>] do_syscall_64+0x33/0x40
[<0>] entry_SYSCALL_64_after_hwframe+0x44/0xa9
  1. 分析锁顺序

进程 A (rename):
  lock(inode_old_dir) -> lock(inode_new_dir)
进程 B (unlink):
  lock(inode_new_dir) -> lock(inode_old_dir)

解决方案

修改代码,确保所有操作按照相同的顺序获取锁:

案例 2:网络子系统循环死锁

问题描述

网络服务在处理大量并发连接时,系统出现 Soft Lockup 警告。

Soft Lockup 报告

分析过程

  1. 使用 perf lock 分析

  1. 使用 bpftrace 跟踪锁持有时间

  1. 发现问题

锁持有链:
  sk_lock -> qdisc_lock -> dev_lock -> sk_lock (循环!)

解决方案

重构代码,打破循环依赖:

效果

  • 消除了循环依赖

  • Soft Lockup 警告消失

  • 网络吞吐量提升 15%

案例 3:内存管理读写锁死锁

问题描述

系统在内存压力下出现 Hung Task 警告,多个进程卡在内存分配上。

Hung Task 报告

分析过程

  1. 查看所有 D 状态进程

  1. 分析锁依赖

进程 A (kswapd0):
  持有: mmap_sem (读锁)
  等待: page_lock
进程 B (allocator):
  持有: page_lock
  等待: mmap_sem (写锁)
进程 C (reader):
  持有: 无
  等待: mmap_sem (读锁) - 被进程 B 阻塞
  1. 问题根源

读写锁的写者优先策略导致:

  • 进程 B 等待写锁,阻塞了所有后续的读者

  • 进程 A 持有读锁,但无法完成(等待 page_lock)

  • 进程 B 等待进程 A 释放读锁

  • 形成死锁

解决方案

方案 1:调整锁粒度

方案 2:使用 trylock 避免死锁

案例 4:驱动程序中断上下文死锁

问题描述

网卡驱动在高负载下出现 Hard Lockup,系统完全无响应。

Hard Lockup 报告

分析过程

  1. 查看驱动代码

  1. 死锁场景

时间线:
  T1: 进程上下文获取 spin_lock(&dev->lock)
  T2: 中断发生,CPU 切换到中断上下文
  T3: 中断处理函数尝试获取 spin_lock(&dev->lock)
  T4: 死锁!中断处理函数在等待进程上下文释放锁
           但进程上下文被中断打断,无法继续执行

解决方案

使用 spin_lock_irqsave() 和 spin_unlock_irqrestore()

关键点

  1. 如果锁会在中断上下文和进程上下文之间共享,必须使用 spin_lock_irqsave()

  2. spin_lock_irqsave() 会禁用本地 CPU 的中断,防止中断处理函数打断当前代码

  3. 必须成对使用 spin_lock_irqsave() 和 spin_unlock_irqrestore()

验证修复


✅ 预防与最佳实践

1. 锁使用原则

原则 1:最小化锁的持有时间

原则 2:保持一致的锁顺序

原则 3:避免在持有锁时调用未知函数

原则 4:正确选择锁类型

2. 使用 lockdep 注解

3. 无锁编程技巧

技巧 1:使用原子操作

技巧 2:使用 RCU

技巧 3:使用 Per-CPU 变量

4. 代码审查检查清单

在代码审查时,检查以下几点:

  • 所有锁的获取和释放是否成对出现?

  • 是否在所有错误路径上都释放了锁?

  • 多个锁的获取顺序是否一致?

  • 是否在持有自旋锁时调用了可能睡眠的函数?

  • 中断上下文和进程上下文共享的锁是否使用了 spin_lock_irqsave()

  • 是否在持有锁时调用了未知的回调函数?

  • 锁的持有时间是否尽可能短?

  • 是否可以使用无锁数据结构代替?

  • 是否正确使用了 lockdep 注解?

  • 是否有文档说明锁的用途和顺序?

5. 开发环境配置

在开发和测试环境中启用死锁检测:

# 内核配置选项
CONFIG_PROVE_LOCKING=y          # 启用 lockdep
CONFIG_LOCK_STAT=y              # 启用锁统计
CONFIG_DEBUG_LOCK_ALLOC=y       # 调试锁分配
CONFIG_DEBUG_SPINLOCK=y         # 调试自旋锁
CONFIG_DEBUG_MUTEXES=y          # 调试互斥锁
CONFIG_DEBUG_ATOMIC_SLEEP=y     # 检测原子上下文中的睡眠
CONFIG_DETECT_HUNG_TASK=y       # 检测 Hung Task
CONFIG_SOFTLOCKUP_DETECTOR=y    # 检测 Soft Lockup
CONFIG_HARDLOCKUP_DETECTOR=y    # 检测 Hard Lockup
# 运行时配置
echo1 > /proc/sys/kernel/lock_stat
echo120 > /proc/sys/kernel/hung_task_timeout_secs
echo1 > /proc/sys/kernel/softlockup_panic

❓ FAQ 常见问题

Q1: 如何区分死锁和活锁?

死锁:进程永久阻塞,等待永远不会发生的事件

  • 进程状态:D (Uninterruptible Sleep)

  • CPU 使用率:0%

  • 特征:进程完全卡住,无法继续执行

活锁:进程不断重试,但无法取得进展

  • 进程状态:R (Running)

  • CPU 使用率:高

  • 特征:进程在运行,但没有实际进展

Q2: Soft Lockup 和 Hard Lockup 有什么区别?

Soft Lockup

  • 定义:CPU 长时间(默认 20 秒)在内核态运行,没有调度其他进程

  • 原因:通常是持有自旋锁时间过长,或者在禁用抢占的情况下执行耗时操作

  • 检测:watchdog 线程定期检查

  • 系统状态:系统仍然响应中断,可以恢复

Hard Lockup

  • 定义:CPU 完全卡住,连中断都无法响应

  • 原因:通常是在禁用中断的情况下死循环,或者硬件故障

  • 检测:NMI watchdog 检测

  • 系统状态:系统完全无响应,通常需要重启

Q3: 为什么 lockdep 报告死锁,但系统没有真正死锁?

lockdep 是静态分析工具,它检测的是潜在的死锁可能性,而不是实际发生的死锁。

原因

  1. lockdep 基于锁的依赖关系,而不是实际的执行路径

  2. 某些锁的获取顺序在实际运行中可能永远不会冲突

  3. 代码中可能有额外的同步机制,但 lockdep 无法识别

处理方式

  • 如果确认不会死锁,使用 lockdep 注解(如 mutex_lock_nested()

  • 重构代码,消除潜在的死锁可能性

  • 不要忽略 lockdep 警告,即使系统目前运行正常

Q4: 如何在生产环境中调试死锁?

生产环境通常不能启用 lockdep(性能开销太大),可以使用以下方法:

方法 1:使用 kdump 收集崩溃转储

# 配置 kdump
vim /etc/default/grub
# 添加:crashkernel=256M
# 重启后验证
cat /proc/cmdline | grep crashkernel
# 触发崩溃(仅用于测试)
echo c > /proc/sysrq-trigger
# 分析转储
crash /usr/lib/debug/vmlinux /var/crash/vmcore

方法 2:使用 sysrq 收集信息

# 启用 sysrq
echo1 > /proc/sys/kernel/sysrq
# 显示所有任务的调用栈
echo t > /proc/sysrq-trigger
# 显示所有 CPU 的状态
echo l > /proc/sysrq-trigger
# 查看 dmesg
dmesg | tail -1000

方法 3:使用 eBPF 监控

Q5: 如何避免在持有锁时分配内存?

问题:在持有自旋锁时使用 GFP_KERNEL 分配内存会导致睡眠,可能引发死锁。

解决方案

方案 1:使用 GFP_ATOMIC

void example1(void) {
spin_lock(&my_lock);
// 使用 GFP_ATOMIC,不会睡眠
void *buffer=kmalloc(SIZEGFP_ATOMIC);
if (!buffer) {
// 处理分配失败
spin_unlock(&my_lock);
return;
    }
// 使用 buffer
spin_unlock(&my_lock);
kfree(buffer);
}

方案 2:在锁外分配内存

void example2(void) {
// 在锁外分配内存
void *buffer=kmalloc(SIZEGFP_KERNEL);
if (!buffer)
return;
spin_lock(&my_lock);
// 使用 buffer
spin_unlock(&my_lock);
kfree(buffer);
}

方案 3:使用内存池

static struct kmem_cache *my_cache;
void init_cache(void) {
my_cache=kmem_cache_create("my_cache",
sizeof(struct my_object),
00NULL);
}
void example3(void) {
spin_lock(&my_lock);
// 从缓存分配,速度快,不会睡眠
struct my_object*obj=kmem_cache_alloc(my_cacheGFP_ATOMIC);
spin_unlock(&my_lock);
// 使用完后释放
kmem_cache_free(my_cacheobj);
}

Q6: 读写锁什么时候会导致死锁?

读写锁的死锁场景:

场景 1:写者饥饿

// 大量读者持续获取读锁,写者永远无法获取写锁
void reader_thread(void) {
while (1) {
read_lock(&rw_lock);
// 读取数据
read_unlock(&rw_lock);
// 很短的间隔
usleep(1);
    }
}
void writer_thread(void) {
// 可能永远无法获取写锁
write_lock(&rw_lock);
// 写入数据
write_unlock(&rw_lock);
}

场景 2:读锁升级

// 尝试将读锁升级为写锁会导致死锁
void upgrade_lock(void) {
read_lock(&rw_lock);
// 检查条件
if (need_write) {
// ❌ 错误:尝试升级锁
// 如果有其他读者,这里会死锁
write_lock(&rw_lock);
// 写入数据
write_unlock(&rw_lock);
    }
read_unlock(&rw_lock);
}
// ✅ 正确做法:释放读锁后重新获取写锁
void correct_upgrade(void) {
read_lock(&rw_lock);
bool need_write=check_condition();
read_unlock(&rw_lock);
if (need_write) {
write_lock(&rw_lock);
// 重新检查条件(可能已改变)
if (check_condition()) {
// 写入数据
        }
write_unlock(&rw_lock);
    }
}

场景 3:递归读锁

// 某些读写锁实现不支持递归
void recursive_read(void) {
read_lock(&rw_lock);
// 调用另一个函数
helper_function();  // 内部也获取读锁
read_unlock(&rw_lock);
}
void helper_function(void) {
read_lock(&rw_lock);  // 可能死锁
// ...
read_unlock(&rw_lock);
}

Q7: 如何处理遗留代码中的死锁问题?

步骤 1:识别问题

# 启用 lockdep(如果可能)
# 运行测试套件
# 收集 lockdep 报告

步骤 2:分析锁依赖

# 使用工具分析锁依赖关系
cat /proc/lockdep_chains | grep -A 10 "your_lock"
# 绘制锁依赖图
# 可以使用 Graphviz 等工具可视化

步骤 3:逐步重构

// 策略 1:拆分大锁
// 将一个保护多个数据结构的大锁拆分为多个小锁
// 策略 2:使用 RCU
// 对于读多写少的场景,使用 RCU 代替读写锁
// 策略 3:使用无锁数据结构
// 使用原子操作、Per-CPU 变量等
// 策略 4:重新设计锁层次
// 建立清晰的锁层次结构,文档化锁顺序

步骤 4:测试验证

# 压力测试
# 使用 lockdep 验证
# 性能测试(确保重构没有引入性能问题)

Q8: 如何在多核系统中调试死锁?

多核系统的死锁调试更加复杂,因为涉及多个 CPU 的并发执行。

技巧 1:使用 CPU 亲和性隔离问题

# 将进程绑定到特定 CPU
taskset -c0 ./test_program
# 在特定 CPU 上运行内核线程
echo1 > /sys/devices/system/cpu/cpu0/online

技巧 2:使用 perf 分析锁竞争

# 记录所有 CPU 的锁事件
perf lock record -a -g sleep 30
# 按 CPU 分析
perf lock report --sort=cpu
# 查看锁竞争热点
perf lock contention -a -b

技巧 3:使用 ftrace 跟踪多 CPU 事件

# 启用所有 CPU 的跟踪
echo1 > /sys/kernel/debug/tracing/options/stacktrace
echo1 > /sys/kernel/debug/tracing/events/lock/enable
# 查看每个 CPU 的事件
cat /sys/kernel/debug/tracing/per_cpu/cpu0/trace
cat /sys/kernel/debug/tracing/per_cpu/cpu1/trace

技巧 4:使用 crash 分析多 CPU 状态

crash> foreach bt
# 显示所有 CPU 的调用栈
crash> ps -m
# 显示每个进程在哪个 CPU 上运行
crash> lock -i
# 显示锁信息

Q9: 如何测试代码是否存在死锁风险?

方法 1:静态分析

# 使用 Coccinelle 检查锁使用
spatch --sp-file check_locks.cocci kernel/
# 使用 sparse 检查
make C=CF="-D__CHECK_ENDIAN__"

方法 2:动态测试

# 启用 lockdep
CONFIG_PROVE_LOCKING=y
# 运行压力测试
stress-ng --all4--timeout 1h
# 使用 syzkaller 进行模糊测试
# https://github.com/google/syzkaller

方法 3:代码审查

使用检查清单(见"预防与最佳实践"部分)

方法 4:使用 ThreadSanitizer

# 对于用户空间程序
gcc -fsanitize=thread -g -O1 program.c
./a.out

Q10: 死锁和优先级反转有什么区别?

死锁

  • 多个进程互相等待对方持有的资源

  • 所有进程都无法继续执行

  • 需要外部干预才能解决

优先级反转

  • 高优先级进程等待低优先级进程持有的锁

  • 中优先级进程抢占低优先级进程

  • 导致高优先级进程被间接阻塞

示例:
  高优先级进程 H:等待锁 L
  中优先级进程 M:运行中
  低优先级进程 L:持有锁 L,但被 M 抢占
结果:H 被 M 间接阻塞,虽然 H 优先级更高

解决方案:优先级继承

// Linux 内核使用 RT-mutex 实现优先级继承
struct rt_mutexmy_lock;
void high_priority_task(void) {
rt_mutex_lock(&my_lock);
// 如果锁被低优先级任务持有,
// 低优先级任务会临时继承高优先级
// ...
rt_mutex_unlock(&my_lock);
}

📖 参考资料

官方文档

  1. Linux Kernel Documentation

    • Locking: https://www.kernel.org/doc/html/latest/locking/index.html

    • lockdep: https://www.kernel.org/doc/html/latest/locking/lockdep-design.html

    • Spinlocks: https://www.kernel.org/doc/html/latest/locking/spinlocks.html

  2. Linux Kernel Source

    • kernel/locking/: 锁实现源码

    • Documentation/locking/: 锁相关文档

书籍推荐

  1. 《Linux Kernel Development》 by Robert Love

    • 第 9 章:An Introduction to Kernel Synchronization

    • 第 10 章:Kernel Synchronization Methods

  2. 《Understanding the Linux Kernel》 by Daniel P. Bovet & Marco Cesati

    • 第 5 章:Kernel Synchronization

  3. 《Linux Device Drivers》 by Jonathan Corbet, Alessandro Rubini & Greg Kroah-Hartman

    • 第 5 章:Concurrency and Race Conditions

  4. 《The Art of Multiprocessor Programming》 by Maurice Herlihy & Nir Shavit

    • 并发编程的理论基础

相关文章

  1. 本系列其他文章

    • 《Linux 内核 Call Trace 完全解析指南》

    • 《Linux 内核 Panic 完全解析指南》

    • 《Linux 内核内存泄漏检测与定位》(即将发布)

  2. 推荐阅读

    • "What every systems programmer should know about lockless programming"

    • "Kernel Locking Techniques" by Rusty Russell

    • "Unreliable Guide To Locking" by Rusty Russell


🎯 总结

死锁是内核开发中最具挑战性的问题之一,但通过系统的方法可以有效预防和解决:

预防死锁

  • 保持一致的锁顺序

  • 最小化锁的持有时间

  • 正确选择锁类型

  • 使用 lockdep 注解

  • 考虑无锁编程

检测死锁

  • 启用 lockdep 进行静态检测

  • 使用 Hung Task、Soft/Hard Lockup 检测器

  • 监控系统日志和进程状态

调试死锁

  • 分析 lockdep 报告

  • 查看进程调用栈

  • 使用 perf、ftrace、eBPF 等工具

  • 在测试环境中重现问题

解决死锁

  • 重构代码,消除循环依赖

  • 调整锁粒度

  • 使用 trylock 避免阻塞

  • 考虑使用 RCU、原子操作等无锁技术

记住,预防永远比治疗更重要。在编写代码时就考虑锁的使用,遵循最佳实践,可以避免大部分死锁问题。


作者注:本文基于 Linux 5.10 内核,不同版本的实现可能有所差异。建议结合实际使用的内核版本查看源码。


如果本文对你有帮助,欢迎分享给更多的内核开发者!有任何问题或建议,欢迎在评论区讨论。

最新文章

随机文章

基本 文件 流程 错误 SQL 调试
  1. 请求信息 : 2026-03-27 13:38:42 HTTP/2.0 GET : https://f.mffb.com.cn/a/483186.html
  2. 运行时间 : 0.238724s [ 吞吐率:4.19req/s ] 内存消耗:5,083.66kb 文件加载:140
  3. 缓存信息 : 0 reads,0 writes
  4. 会话信息 : SESSION_ID=588972f099f6b2082fc2a893f606270d
  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.001013s ] mysql:host=127.0.0.1;port=3306;dbname=f_mffb;charset=utf8mb4
  2. SHOW FULL COLUMNS FROM `fenlei` [ RunTime:0.001819s ]
  3. SELECT * FROM `fenlei` WHERE `fid` = 0 [ RunTime:0.001643s ]
  4. SELECT * FROM `fenlei` WHERE `fid` = 63 [ RunTime:0.000729s ]
  5. SHOW FULL COLUMNS FROM `set` [ RunTime:0.001452s ]
  6. SELECT * FROM `set` [ RunTime:0.000627s ]
  7. SHOW FULL COLUMNS FROM `article` [ RunTime:0.001610s ]
  8. SELECT * FROM `article` WHERE `id` = 483186 LIMIT 1 [ RunTime:0.001473s ]
  9. UPDATE `article` SET `lasttime` = 1774589922 WHERE `id` = 483186 [ RunTime:0.006425s ]
  10. SELECT * FROM `fenlei` WHERE `id` = 67 LIMIT 1 [ RunTime:0.000793s ]
  11. SELECT * FROM `article` WHERE `id` < 483186 ORDER BY `id` DESC LIMIT 1 [ RunTime:0.004953s ]
  12. SELECT * FROM `article` WHERE `id` > 483186 ORDER BY `id` ASC LIMIT 1 [ RunTime:0.001309s ]
  13. SELECT * FROM `article` WHERE `id` < 483186 ORDER BY `id` DESC LIMIT 10 [ RunTime:0.002740s ]
  14. SELECT * FROM `article` WHERE `id` < 483186 ORDER BY `id` DESC LIMIT 10,10 [ RunTime:0.006952s ]
  15. SELECT * FROM `article` WHERE `id` < 483186 ORDER BY `id` DESC LIMIT 20,10 [ RunTime:0.013273s ]
0.241943s