require 'rubygems'
require 'mechanize'
require 'io/console'
flag = 0
t2 =Thread.new do
puts flag
loop do
temp = STDIN.getch
if temp=="\n"
flag = (flag+1)%2
puts flag
end
end
end
# => Some foreground code
t2.join
当我运行代码时,我得到了flag
打印0
的值。但是线程不会更改{strong>第一个 Enter 我点击的flag
的值。点击输入,第二次将标志更改为1
。该线程通常在进一步 Enter 命中时切换flag
的值。为什么会这样?我做错了什么?
问题似乎仅适用于getch
就像当我使用gets
代替getch
时,问题就消失了。但是我不能使用gets
,因为我希望用户只需按下 Enter 键即可点击一个键来输入。
例如,当用户输入 a 而不是 Enter 时,flag
不应该更改,因此我使用getch
确保输入是在单击键盘。
描述了一个类似的问题here,但它并不重复。
编辑1:
问题似乎是getch
,而不是检查是什么。
flag = 0
t2 =Thread.new do
puts flag
loop do
temp = STDIN.getch
flag = (flag+1)%2
puts flag
end
end
t2.join
即使删除了if语句,第一次 Enter 也会被忽略,不管其他字符似乎第一次响应。只有当我点击 Enter 时才会出现问题。它没有计算我点击的第一个 Enter 。
ruby 2.3.3p222 (2016-11-21 revision 56859) [x64-mingw32]
答案 0 :(得分:1)
我在Windows机器上尝试了您的代码,并且能够重新创建问题。正如你所猜测的那样,它与线程无关,以及getch
如何工作(在Windows上)。
如果你在你的循环中添加一个p temp.inspect
,你会发现它并不是第一个'\ n'被吞下,而是它以某种方式被“阻止”。如果您按 Enter 和另一个键,最好的方法是看到这个。您将看到检查是“一个接一个”。
这里讨论关于这个问题的一个很好的解释: https://www.rubytapas.com/2016/12/14/ruby-code-on-windows/
有了这些信息,一个简单的解决方案(在Linux上运行也有额外的好处,不确定Mac)是:
require 'rubygems'
require 'mechanize'
require 'io/console'
STDIN.binmode #this line added to prevent line-end translation
flag = 0
t2 =Thread.new do
puts flag
loop do
temp = STDIN.getch
if temp=="\r" # note: changed from LF to CR
flag = (flag+1)%2
puts flag
end
end
end
# => Some foreground code
t2.join
注意: 不可否认,我并没有完全了解它的工作方式。我期待 Enter 会在binmode中产生“\ r \ n”序列,但我只看到“\ r”。不确定“\ n”会发生什么,但它似乎以这种方式可靠地工作。 另请注意,在当前版本中,程序无法使用 Ctrl + C 终止。你必须为此添加一张支票。