c - __sync_fetch_and_add() 的信号安全
问题描述
我有一个接受套接字客户端并分叉子进程的程序。为了保持子进程的计数,我使用了一个全局变量,原子函数用于递增和递减计数。
我担心 __sync_fetch_and_add() 的信号安全。当多个孩子频繁连接和断开时,是否存在死锁的可能性。
下面是我的代码片段。
int main()
{
...
signal(SIGCHLD, handle_sigchild);
...
if ((pid = fork()) == -1) {
close(sock);
continue;
} else if (pid > 0) { //Parent
__sync_fetch_and_add(&counter, 1);
close(sock);
continue;
} else if (pid == 0) {
...
}
...
}
// Signal Handler
void handle_sigchild(int arg)
{
while( waitpid(-1, NULL, WNOHANG) > 0){
__sync_fetch_and_add(&counter, -1);
}
signal(SIGCHLD, handle_sigchild);
}
解决方案
原子函数通常实现为围绕执行实际操作的关键指令的循环,在这种情况下可能会失败,需要重试。
任何冲突都会导致关键指令失败,这也适用于信号处理程序引入的冲突。
例如,fetch-and-add通常类似于
.L2:
lwarx 10,0,3
addi 9,10,1
stwcx. 9,0,3
bne 0,.L2
extsw 3,10
blr
因此,加载该值并进行预订,然后递增,然后如果预订仍然有效,则将其存储回来。如果失败,我们重新开始获取新值(因为很可能有人在此期间写过)。
在 Intel 上,这个过程隐藏在里面
mov eax, 1
lock xadd DWORD PTR [rdi], eax
ret
在旧机器上,这确实会在 add 指令期间锁定整个总线,在较新的机器上,它会默默地在微码中生成一个循环,反复尝试增加值。
任何中断(传递信号所必需的)只会延长加载和存储之间的时间,这使得当前迭代更有可能无法更新值,因为其他东西更快。
推荐阅读
- ms-access - MSAccess 事件错误,仅在某些时候触发,其他时候不会触发
- php - 构建 PHP 回显语句数组以通过 Ajax 调用返回的问题(不工作)
- javascript - 错误:viewType“resourceTimelineDay”不可用。请确保您已加载所有必要的插件
- c++ - ORA-01455: 转换列溢出整数数据类型
- c++ - MySQL DELETE 查询不会从 C++ 代码中删除元素
- java - Retrofit 2.9.0 中的多部分请求为空
- r - 调整模型多重比较的 p 值的最简单方法,以使用 modelsummary 包中的 msummary 显示
- git - 如何使用 Github 访问码自动登录?
- android - Android Deeplink URL 端点处理
- sql-server - SQL Server:如何在另一个子字符串的最后一次出现之后和下一个逗号之前找到子字符串