> For the complete documentation index, see [llms.txt](https://man.bsdcn.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://man.bsdcn.org/man9/critical_enter.9.md).

# critical\_enter(9)

`critical_enter` — 进入和退出临界区

## 名称

`critical_enter`, `critical_exit`

## 概要

```c
#include <sys/param.h>
#include <sys/systm.h>

void
critical_enter(void)

void
critical_exit(void)

void
CRITICAL_ASSERT(struct thread *td)
```

## 描述

这些函数用于防止代码在临界区内被抢占。所能保证的是当前在 CPU 上执行的线程不会被抢占。具体而言，处于临界区中的线程不会在临界区内迁移到另一个 CPU，当前 CPU 也不会切换到不同的线程。当前 CPU 在临界区内仍可能触发故障和异常；不过，这些故障通常是致命的。

CPU 也可能在临界区内接收并处理中断。当这种情况发生时，中断退出不会导致上下文切换，执行将继续在临界区内进行。因此，临界区对当前线程执行的净影响类似于在禁用中断的情况下运行，不同之处在于定时器中断和过滤的中断处理程序不会产生延迟惩罚。

`critical_enter` 和 `critical_exit` 函数管理一个每线程计数器以处理嵌套的临界区。如果在当前线程处于临界区时，有一个本应抢占当前线程的线程被置为可运行状态，则抢占会延迟到当前线程退出最外层临界区时。

注意，这些函数不提供任何 CPU 间同步、数据保护或内存顺序保证，因此*不应*用于保护共享数据结构。

使用这些函数时应谨慎，因为在临界区内出现无界或无限循环会导致 CPU 死锁。此外，它们不应与互斥锁、sx 锁、信号量或其他同步原语上的操作相互锁定，因为这些原语可能需要上下文切换才能操作。一个例外是自旋互斥锁包含一个临界区，因此在某些情况下临界区可以与自旋互斥锁相互锁定。

临界区应仅设置为必要的宽度。也就是说，不需要在临界区内才能正确运行的代码应尽可能排除在临界区范围之外。滥用临界区会影响整体系统延迟和定时器精度，因为禁用抢占会延迟线程化中断处理程序和当前 CPU 上的 [callout(9)](/man9/callout.9.md) 事件的执行。

`CRITICAL_ASSERT` 宏验证所提供的线程 `td` 当前正在临界区内执行。它是 [KASSERT(9)](/man9/kassert.9.md) 的封装。

## 参见

[callout(9)](/man9/callout.9.md), [KASSERT(9)](/man9/kassert.9.md), [locking(9)](/man9/locking.9.md)

## 历史

这些函数引入于 FreeBSD 5.0。
