gpt4 book ai didi

c - 为什么在 Mac OS X 上 fork 后 tzset() 会慢很多?

转载 作者:太空狗 更新时间:2023-10-29 14:56:06 33 4
gpt4 key购买 nike

fork 后调用 tzset() 似乎很慢。如果我在 fork 之前首先在父进程中调用 tzset() ,我只会看到速度缓慢。我的 TZ 环境变量未设置。我 dtruss 测试程序,它显示子进程读取 /etc/localtime 每次 tzset() 调用,而父进程只读一次。此文件访问似乎是缓慢的根源,但我无法确定为什么它每次都在子进程中访问它。

这是我的测试程序 foo.c:

#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <unistd.h>

void check(char *msg);

int main(int argc, char **argv) {
check("before");

pid_t c = fork();
if (c == 0) {
check("fork");
exit(0);
}

wait(NULL);

check("after");
}

void check(char *msg) {
struct timeval tv;

gettimeofday(&tv, NULL);
time_t start = tv.tv_sec;
suseconds_t mstart = tv.tv_usec;

for (int i = 0; i < 10000; i++) {
tzset();
}

gettimeofday(&tv, NULL);
double delta = (double)(tv.tv_sec - start);
delta += (double)(tv.tv_usec - mstart)/1000000.0;

printf("%s took: %fs\n", msg, delta);
}

我像这样编译并执行了 foo.c:

[muir@muir-work-mb scratch]$ clang -o foo foo.c
[muir@muir-work-mb scratch]$ env -i ./foo
before took: 0.002135s
fork took: 1.122254s
after took: 0.001120s

我正在运行 Mac OS X 10.10.1(也在 10.9.5 上复制)。

我最初是通过 ruby​​ 注意到速度缓慢的(子进程中的 Time#localtime 慢)。

最佳答案

Ken Thomases 的回答可能是正确的,但我对更具体的答案感到好奇,因为我仍然发现单线程程序在 forking 之后执行如此简单/常见的操作时的缓慢意外行为.检查后http://opensource.apple.com/source/Libc/Libc-997.1.1/stdtime/FreeBSD/localtime.c (不是 100% 确定这是正确的来源),我想我有一个答案。

该代码使用被动通知来确定时区是否已更改(而不是每次都在 stating /etc/localtime 中)。在 forking 之后,注册的通知 token 似乎在子进程中变得无效。此外,代码将使用无效 token 的错误视为时区已更改的肯定通知,并继续每次读取 /etc/localtime。我想这就是您在 forking 之后可以得到的那种未定义行为?不过,如果图书馆注意到错误并重新注册通知,那就太好了。

这是来自 localtime.c 的代码片段,它混合了错误值和状态值:

nstat = notify_check(p->token, &ncheck);
if (nstat || ncheck) {

我演示了使用这个程序 fork 后注册 token 变得无效:

#include <notify.h>
#include <stdio.h>
#include <stdlib.h>

void bail(char *msg) {
printf("Error: %s\n", msg);
exit(1);
}

int main(int argc, char **argv) {
int token, something_changed, ret;

notify_register_check("com.apple.system.timezone", &token);

ret = notify_check(token, &something_changed);
if (ret)
bail("notify_check #1 failed");
if (!something_changed)
bail("expected change on first call");

ret = notify_check(token, &something_changed);
if (ret)
bail("notify_check #2 failed");
if (something_changed)
bail("expected no change");

pid_t c = fork();
if (c == 0) {
ret = notify_check(token, &something_changed);
if (ret) {
if (ret == NOTIFY_STATUS_INVALID_TOKEN)
printf("ret is invalid token\n");

if (!notify_is_valid_token(token))
printf("token is not valid\n");

bail("notify_check in fork failed");
}

if (something_changed)
bail("expected not changed");

exit(0);
}

wait(NULL);
}

然后像这样运行它:

muir-mb:projects muir$ clang -o notify_test notify_test.c 
muir-mb:projects muir$ ./notify_test
ret is invalid token
token is not valid
Error: notify_check in fork failed

关于c - 为什么在 Mac OS X 上 fork 后 tzset() 会慢很多?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27932330/

33 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com