以下
Ruby代码生成所有预期输出但未正确退出.在完成each_byte循环之前,它会挂起 – 消耗100%的CPU – 直到进程被终止.
f = File.new(ARGV.shift)
i = 0
f.each_byte {printf("%08X\n", f.pos - 1) if (i += 1) % 16 == 1}
f.close
我试过用很多不同的方式设计循环(用i代替f.pos的用法,反之亦然),它们都工作正常!只有这一种方法导致它挂起,我不知道为什么.
有任何想法吗?
最佳答案 好的..因为运行测试代码不需要任何外部ruby库我可以在我的机器上编译1.9而不安装它,并运行测试程序.
这是我看到的:
> Ruby似乎“挂起”(你不能打断它,它本身不会退出).
> top显示ruby以100%CPU运行
> strace进入100%CPU模式后显示无输出.
从这一点来看,很明显Ruby进入了无限循环.在io.c中查看each_byte,并在可疑位置添加printf,可以发现我们陷入困境的地方:
static VALUE
rb_io_each_byte(VALUE io)
{
rb_io_t *fptr;
char *p, *e;
RETURN_ENUMERATOR(io, 0, 0);
GetOpenFile(io, fptr);
for (;;) {
p = fptr->rbuf+fptr->rbuf_off;
e = p + fptr->rbuf_len;
printf("UH OH: %d < %d\n", p, e); /* INFINITE LOOP ALERT */
while (p < e) {
fptr->rbuf_off++;
fptr->rbuf_len--;
rb_yield(INT2FIX(*p & 0xff));
p++;
errno = 0;
}
rb_io_check_byte_readable(fptr);
READ_CHECK(fptr);
if (io_fillbuf(fptr) < 0) {
break;
}
}
return io;
}
在我的机器上它打印出来:
UH OH: 0 < 0
UH OH: 137343104 < 137351296
UH OH: 137343119 < 137343104
UH OH: 137343119 < 137343104
UH OH: 137343119 < 137343104
...ad infinitum...
并且137343119不小于137343104,这意味着我们停止进入while循环(这将产生块).
当您运行代码以使其不挂起时,您会得到:
UH OH: 0 < 0
UH OH: 137341560 < 137349752
UH OH: 137341560 < 137349752
UH OH: 137341560 < 137349752
UH OH: 137341560 < 137349752
....
并且137341560 IS小于137349752.
无论如何..这就是我现在所拥有的一切.仍然不知道为什么会发生这种情况.但现在我们至少知道发生了什么.编写该代码的人可能会解释为什么它会立即发生.
无论如何..我仍然认为lseek调用某种方式搞乱了ruby的内部文件指针,上面的循环因此而变得混乱.
编辑
这是一个修复:
在io.c中更改flush_before_seek看起来像这样:
static rb_io_t *
flush_before_seek(rb_io_t *fptr)
{
int wbuf_len = fptr->wbuf_len;
if (io_fflush(fptr) < 0)
rb_sys_fail(0);
if (wbuf_len != 0)
io_unread(fptr);
errno = 0;
return fptr;
}
我添加的是检查wbuf_len!= 0,这样我们就不会不必要地执行io_unread了.在each_byte循环中调用io_unread是令人烦恼的事情.跳过未读使得工作正常,所有make测试仍然通过.
无论如何..这不是一个正确的解决方案,因为f.pos存在一些基本的思想错误.这只是一个解决方法……但它解决了上述问题: – /