加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

Ruby File IO Hang

发布时间:2020-12-17 02:11:40 所属栏目:百科 来源:网络整理
导读:以下 Ruby代码生成所有预期输出但未正确退出.在完成each_byte循环之前,它会挂起 – 消耗100%的CPU – 直到进程被终止. f = File.new(ARGV.shift)i = 0f.each_byte {printf("%08Xn",f.pos - 1) if (i += 1) % 16 == 1}f.close 我试过用很多不同的方式设计循
以下 Ruby代码生成所有预期输出但未正确退出.在完成each_byte循环之前,它会挂起 – 消耗100%的CPU – 直到进程被终止.

f = File.new(ARGV.shift)
i = 0
f.each_byte {printf("%08Xn",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);
    GetOpenFile(io,fptr);

    for (;;) {
        p = fptr->rbuf+fptr->rbuf_off;
        e = p + fptr->rbuf_len;

        printf("UH OH: %d < %dn",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存在一些基本的思想错误.这只是一个解决方法……但它解决了上述问题: – /

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读