Ruby - fork,exec,detach ....我们这里有竞争条件吗?

use*_*428 13 ruby cygwin

简单的例子,它不适用于我的平台(Ruby 2.2,Cygwin):

#!/usr/bin/ruby
backtt = fork { exec('mintty','/usr/bin/zsh','-i') }
Process.detach(backtt)
exit
Run Code Online (Sandbox Code Playgroud)

这个小程序(从shell启动时)应该跨越一个终端窗口(mintty),然后让我回到shell提示符.

然而,虽然它创建了薄荷窗口,但之后我没有shell提示符,并且我无法在调用shell中键入任何内容.

但是当我在分离之前引入一个小延迟时,要么使用'sleep',要么在stdout上打印一些内容,它会按预期工作:

#!/usr/bin/ruby
backtt = fork { exec('mintty','/usr/bin/zsh','-i') }
sleep 1
Process.detach(backtt)
exit
Run Code Online (Sandbox Code Playgroud)

为什么这有必要?

顺便说一下,我很清楚我可以(从外壳)做一个

mintty /usr/bin/zsh -i &
Run Code Online (Sandbox Code Playgroud)

直接,或者我可以...... &从Ruby内部使用system(),但这不是重点.我特别感兴趣的fork/exec/detach是Ruby 中的行为.任何见解?

hal*_*bit 6

发布作为答案,因为评论太长了

虽然我不是Ruby的专家,根本不了解Cygwin,但这种情况对我来说非常熟悉,来自C/C++.

此脚本太短,因此父级的父级完成,而孙级尝试启动.

如果您在分离后和退出前进行睡眠会发生什么?

如果我的理论是正确的,它也应该有效.您的程序在任何(或足够的)线程切换发生之前退出.

我把这些问题称为"中断的手抖动".虽然这是心理学术语,但它描述了会发生什么.

睡眠"放弃时间片",导致线程切换,

控制台输出(任何文件I/O)运行到信号量,也导致线程切换.

如果我的想法是正确的,它也应该工作,如果你不"睡觉",只计数到1e9(取决于计算的速度),因为然后抢占式多任务使得甚至线程切换本身也不会放弃CPU.

所以这是编程中的一个错误(恕我直言:在这种情况下竞争条件是哲学的),但很难找到"谁"负责.涉及很多事情.

  • 所以我的假设不正确,这只是一个想法,因为看起来很熟悉,这就是为什么我只想评论,而不是回答, - 不知道如何删除'50' (4认同)

Ale*_*kin 0

根据文档

\n\n
\n

Process::detach通过设置一个单独的 Ruby 线程来防止这种情况,该线程的唯一工作是在进程终止时获取进程 pid 的状态。

\n
\n\n

注意:我不能在任何可用的操作系统上重现此行为,并且我将其发布为答案只是为了格式化。

\n\n

由于Process.detach(backtt)透明地创建了一个线程,我建议您尝试:

\n\n
#!/usr/bin/ruby\nbacktt = fork { exec(\'mintty\',\'/usr/bin/zsh\',\'-i\') }\n#                     \xe2\x87\x93\xe2\x87\x93\xe2\x87\x93\xe2\x87\x93\xe2\x87\x93\nProcess.detach(backtt).join\nexit\n
Run Code Online (Sandbox Code Playgroud)\n\n

这无论如何都不是黑客行为(与愚蠢相反sleep),因为您可能知道底层命令应该或多或少立即返回。我不是 cygwin 的专家,但它可能对线程有一些特定的问题,所以,让这个线程被处理。

\n