异常处理机制
POSIX 异常处理机制总结
一、核心机制
POSIX 异常处理主要依赖以下机制管理运行时错误和信号:
1. 错误返回与 errno
-
错误标识:
POSIX 系统调用和库函数通过返回值指示错误(通常返回-1
或NULL
),并通过全局变量errno
存储具体错误码。- 示例:
- 示例:
-
errno
的特性:- 线程安全:现代实现中,
errno
是线程局部变量(每个线程独立维护)。 - 易失性:函数调用可能覆盖
errno
,需在失败后立即保存其值。
- 线程安全:现代实现中,
2. 错误处理函数
-
perror()
:
根据当前errno
输出可读错误信息到stderr
。
-
strerror()
:
将错误码转换为字符串,适合自定义日志格式。
3. 信号(Signals)
信号是异步异常通知机制,用于处理进程外部事件(如 SIGSEGV
、SIGINT
)。
-
信号处理函数:
-
signal()
:简单注册信号处理函数(不推荐,兼容性差)。
-
sigaction()
:更安全的信号处理方式,支持精细控制。
-
-
常见信号类型:
信号 | 含义 | 默认行为 |
---|---|---|
SIGSEGV |
非法内存访问(段错误) | 终止进程 |
SIGFPE |
算术异常(如除零) | 终止进程 |
SIGINT |
终端中断(Ctrl+C) | 终止进程 |
SIGPIPE |
管道或Socket写入端关闭 | 终止进程 |
SIGCHLD |
子进程状态变化 | 忽略 |
- 信号处理注意事项:
- 信号处理函数应尽量简单,避免调用非异步安全函数(如
printf
、malloc
)。 - 使用
volatile sig_atomic_t
类型标记异步事件。
- 信号处理函数应尽量简单,避免调用非异步安全函数(如
4. 资源错误处理
-
动态内存分配:
-
文件与IO错误:
- 文件不存在(
ENOENT
)、权限不足(EACCES
)、设备已满(ENOSPC
)等。 - 示例:
- 文件不存在(
5. 线程错误处理
POSIX 线程(pthread)函数通过返回值传递错误码(而非设置 errno
)。
- 示例:
pthread_t thread;
int ret = pthread_create(&thread, NULL, worker_func, NULL);
if (ret != 0) {
// 错误码在返回值中(如 EAGAIN、EINVAL)
fprintf(stderr, "Thread creation failed: %s\n", strerror(ret));
}
二、最佳实践
-
严格检查返回值:
对所有可能失败的函数调用检查返回值(尤其是系统调用和库函数)。 -
及时处理
errno
:- 在函数失败后立即保存
errno
,避免被后续调用覆盖。 - 使用
perror()
或strerror()
输出错误信息。
- 在函数失败后立即保存
-
信号处理安全:
- 使用
sigaction
替代signal
。 - 避免在信号处理函数中执行复杂操作。
- 使用
-
资源清理:
确保在错误退出前释放已分配的资源(如关闭文件描述符、释放内存)。 -
错误码分类处理:
根据errno
值选择重试、回退或终止程序。
三、总结
POSIX 异常处理的核心是通过 返回值 + errno
标识错误,结合 信号 处理异步事件。关键要点:
- 系统调用错误依赖
errno
,线程错误通过返回值传递。 - 使用
perror
/strerror
转换错误码为可读信息。 - 信号处理需保证安全性和简单性。
- 资源错误需及时清理,避免泄漏。
通过合理利用这些机制,可以构建健壮且可维护的系统程序。