可重入函数与信号安全函数
1. 从 不可重入 到 可重入
可重入指,函数被并发调用。
若函数写 全局变量,则不可重入,改为 堆分配,则可重入。
2. 从 可重入 到 信号安全
信号安全指,函数A执行途中,处理信号,信号处理函数中 又调用 函数A。
若函数使用 全局变量,则信号不安全。若改为 堆分配,也不安全,因为 malloc使用了锁,
所以函数使用 锁,则信号不安全,因为,函数执行途中已获得锁,但由于处理信号,有需要申请锁,导致死锁。
3. 怎么知道函数是否安全
可重入函数 后面 通常 加了 _r
信号安全函数 使用 man 7 signal 查看
4. 怎么避免信号导致不安全
首先 信号内使用 系统调用是安全的,所以将 信号转换为 pipe,通过监听pipe 处理信号。
应注意pipe应设置为 非阻塞,否则由于 管道满导致 写阻塞,导致死锁。
5. 示例
5.1 ngx对 strerror的处理
由于 strerror 不是 Async-Signal-Safe,所以采用预读取所有 errno 信息
static ngx_str_t ngx_unknown_error = ngx_string("Unknown error");
static ngx_str_t *ngx_sys_errlist;
static ngx_err_t ngx_first_error;
static ngx_err_t ngx_last_error;
u_char *
ngx_strerror(ngx_err_t err, u_char *errstr, size_t size)
{
ngx_str_t *msg;
if (err >= ngx_first_error && err < ngx_last_error) {
msg = &ngx_sys_errlist[err - ngx_first_error];
} else {
msg = &ngx_unknown_error;
}
size = ngx_min(size, msg->len);
return ngx_cpymem(errstr, msg->data, size);
}
ngx_int_t
ngx_strerror_init(void)
{
char *msg;
u_char *p;
size_t len;
ngx_err_t err;
ngx_first_error = 0;
ngx_last_error = NGX_SYS_NERR; // errno 数量
len = (ngx_last_error - ngx_first_error) * sizeof(ngx_str_t);
ngx_sys_errlist = malloc(len);
if (ngx_sys_errlist == NULL) {
goto failed;
}
for (err = ngx_first_error; err < ngx_last_error; err++) {
msg = strerror(err);
if (msg == NULL) {
ngx_sys_errlist[err - ngx_first_error] = ngx_unknown_error;
continue;
}
len = ngx_strlen(msg);
p = malloc(len);
if (p == NULL) {
goto failed;
}
ngx_memcpy(p, msg, len);
ngx_sys_errlist[err - ngx_first_error].len = len;
ngx_sys_errlist[err - ngx_first_error].data = p;
}
return NGX_OK;
failed:
err = errno;
ngx_log_stderr(0, "malloc(%uz) failed (%d: %s)", len, err, strerror(err));
return NGX_ERROR;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?