linux – sleep毫秒 – Bash:无限的睡眠(无限的阻挡)

from–https://code-examples.net/zh-CN/q/2cc98f

 

 

bash sleep ms (9)

tail不阻挡

一如既往:对于所有事情,都有一个简短,易于理解,易于遵循且完全错误的答案。 这里tail -f /dev/null属于这个类别;)

如果你用strace tail -f /dev/null来看它,你会注意到,这个解决方案远非阻塞! 这可能比问题中的sleep解决方案还要糟糕,因为它使用(在Linux下)像inotify系统这样的宝贵资源。 写入/dev/null其他进程/dev/null导致tail循环。 (在我的Ubuntu64 16.10上,这在已经繁忙的系统上每秒增加几十个系统调用。)

问题是阻塞命令

不幸的是,没有这样的事情..

阅读:我不知道任何方式直接存档与外壳。

一切(甚至sleep infinity )都可能被一些信号中断。 所以如果你想确定它不会异常返回,它必须在循环中运行,就像你已经为你的sleep做了一样。 请注意,(在Linux上) /bin/sleep显然是在24天限制的(看看strace sleep infinity ),因此最好的做法可能是:

while :; do sleep 2073600; done

(请注意,我相信sleep内部循环的值高于24天,但这意味着:它不会阻塞,它非常缓慢地循环,所以为什么不把它移到外面?)

..但你可以非常接近一个无名的fifo

只要没有信号发送到进程,您就可以创建一个真正阻塞的东西。 以下使用bash 4个PID和1个fifo :

bash -c 'coproc { exec >&-; read; }; eval exec "${COPROC[0]}<&-"; wait'

如果你喜欢,你可以检查这是否真的阻止了strace :

strace -ff bash -c '..see above..'

这是如何构建的

如果没有输入数据,则read块(请参阅其他答案)。 但是, tty ( stdin )通常不是一个好的源,因为它在用户注销时关闭。 它也可能从tty窃取一些输入。 不太好。

为了使read块,我们需要等待像fifo这样的东西,永远不会返回任何东西。 在bash 4有一个命令可以准确地为我们提供这样一个fifo : coproc 。 如果我们也等待阻塞read (这是我们的coproc ),我们就完成了。 可悲的是,这需要保持开放的两个PID和一个fifo 。

一个名为fifo变体

如果你不打扰使用命名的fifo ,你可以这样做,如下所示:

mkfifo "$HOME/.pause.fifo" 2>/dev/null; read <"$HOME/.pause.fifo"

读取时不使用循环有点草率,但可以随时重复使用此fifo ,并使用touch "$HOME/.pause.fifo"使read终止(如果有多个读取等待,全部都立即终止)。

或者使用Linux pause()系统调用

对于无限的阻塞,有一个叫做pause()的Linux内核调用,它做我们想要的:永远等待(直到信号到达)。 然而,这(尚)没有用户空间程序。

C

创建这样的程序很容易。 下面是创建一个叫做pause的非常小的Linux程序片断,它会无限期地暂停(需要diet , gcc等):

printf '#include <unistd.h>\nint main(){for(;;)pause();}' > pause.c;
diet -Os cc pause.c -o pause;
strip -s pause;
ls -al pause

python

如果你不想自己编译一些东西,但你已经安装了python ,你可以在Linux下使用它:

python -c 'while 1: import ctypes; ctypes.CDLL(None).pause()'

(注意:使用exec python -c ...来替换当前的shell,这可以释放一个PID,并且可以通过一些IO重​​定向来改进解决方案,释放未使用的FD,这取决于您。

这是如何工作的(我认为): ctypes.CDLL(None)加载标准的C库,并在一些额外的循环内运行pause()函数。 效率低于C版本,但有效。

我对你的建议是:

留在循环睡眠。 它很容易理解,非常便携,并且大部分时间都会阻塞。

我使用startx来启动X来评估我的.xinitrc 。 在我的.xinitrc我使用/usr/bin/mywm启动窗口管理器。 现在,如果我杀了我的WM(为了测试其他WM),X也会终止,因为.xinitrc脚本到达了EOF。 所以我在.xinitrc的末尾加入了这个:

while true; do sleep 10000; done

这样,如果我杀死我的WM,X将不会终止。 现在我的问题是:我如何做一个无限的睡眠而不是循环睡眠? 有没有一个命令可能会让脚本冻结?

最好的祝福


TL; DR: sleep infinity实际上睡眠允许的最大时间,这是有限的。

想知道为什么这个没有记录在任何地方,我懒得读一下GNU coreutils源代码 ,我发现它大致执行如下:

  1. 在第一个参数中使用C stdlib的strtod将’infinity’转换为双精度。 所以,假设IEEE 754双精度,64位正无穷大值存储在seconds变量中。
  2. 调用xnanosleep(seconds) ( 在gnulib中找到 ),这又调用dtotimespec(seconds) (也在gnulib中)doublestruct timespec转换为struct timespec 。
  3. struct timespec只是一对整数:整数部分(以秒为单位)和小数部分(以纳秒为单位)。 天真地将正无穷大转换为整数会产生未定义的行为(参见C标准的第6.3.1.4节),所以它会截断为TYPE_MAXIMUM (time_t) 。
  4. TYPE_MAXIMUM (time_t)的实际值不在标准中(甚至sizeof(time_t)不是); 所以,为了举例,我们从最近的linux内核中选择x86-64。

这是Linux内核中的TIME_T_MAX ,它被定义为( time.h ):

(time_t)((1UL << ((sizeof(time_t) << 3) - 1)) - 1)

请注意, time_t__kernel_time_t , time_tlong ; 使用LP64数据模型,所以sizeof(long)是8(64位)。

这产生: TIME_T_MAX = 9223372036854775807 。

即: sleep infinite导致实际睡眠时间为9223372036854775807秒(10 ^ 11年)。 对于32位Linux系统( sizeof(long)是4(32位)):2147483647秒(68年;另见2038年问题)。

编辑 :显然,调用的nanoseconds函数不是直接的系统调用,而是依赖操作系统的包装器(也在gnulib中定义 )。

结果有一个额外的步骤:对于HAVE_BUG_BIG_NANOSLEEPtrue的某些系统,睡眠会被截断为24天,然后调用一个循环。 一些(或全部)Linux发行版就是这种情况。 请注意,如果配置时间测试成功( source ),则可能不会使用此包装。

特别是,这将是24 * 24 * 60 * 60 = 2073600 seconds (加上999999999纳秒); 但为了尊重指定的总睡眠时间,这被称为循环。 因此,先前的结论仍然有效。

总之,所产生的睡眠时间不是无限的,但对于所有实际目的而言都足够高 ,即使由此产生的实际时间流逝不是便携式的; 这取决于操作系统和体系结构。

要回答原始问题,这显然已经足够好了,但如果出于某种原因( 非常资源受限的系统),您真的想要避免无用的额外倒计时器,我想最正确的选择是使用其他方法中描述的cat方法答案。


sleep infinity正是它的建议和工作没有猫虐待。


sleep infinity看起来最优雅,但有时​​由于某种原因不起作用。 在这种情况下,您可以尝试其他阻止命令,例如cat , read , tail -f /dev/null , grep a等。


不要杀死窗口管理器,而应尝试使用--replace-replace如果可用)运行新窗口。


也许这看起来很丑,但为什么不运行cat ,让它永远等待输入?


发送一个SIGSTOP到自己呢?

这应该暂停进程,直到收到SIGCONT。 你的情况是:从不。

kill -STOP "$$";
# grace time for signal delivery
sleep 60;

我最近有需要这样做。 我想出了下面这个函数,它允许bash永远睡觉而不需要调用任何外部程序:

snore()
{
    [[ -n "${_snore_fd:-}" ]] || exec {_snore_fd}<> <(:)
    read ${1:+-t "$1"} -u $_snore_fd || :
}

注意:我以前发布过这样一个版本,每次都会打开和关闭文件描述符,但是我发现在某些系统上每秒钟执行数百次最终会锁定。 因此,新解决方案在调用函数之间保留文件描述符。 无论如何,Bash会在退出时清理它。

这可以像/ bin / sleep一样调用,它会在请求的时间内休眠。 没有参数调用,它将永远挂起。

snore 0.1  # sleeps for 0.1 seconds
snore 10   # sleeps for 10 seconds
snore      # sleeps forever

这里有一篇关于我的博客的详细资料


while :; do read; done

没有等待孩子睡觉的过程。

上一篇
下一篇