c语言 - dup( fileno( stdin ) ),然后生成 32 个线程 - > I/O 错误



我写了 Zsh 模块。在那里,我有一个映射到 Zsh 命令的内置函数。此函数复制其 stdin 文件描述符:

/* Duplicate standard input */
oconf->stream = fdopen( dup( fileno( stdin ) ), "r" );

然后生成一个线程,获取oconf结构。在该线程中,我确实:

errno = 0;
/* Read e.g. 5 characters, putting them after previous portion */
int count = fread( buf + index, 1, read_size, oconf->stream );
/* Ensure that our whole data is a string - null terminated */
buf[ index + count ] = '';
if ( errno ) {
fprintf( oconf->err, "Read error (descriptor: %d): %sn", fileno( oconf->stream ), strerror( errno ) >
}

如果我在 zsh 中生成 32 个线程:

for (( i=1; i<=32; i ++ )); do
ls -R /Users/myuser/Documents | mybuiltin -A myhash_$i $i
done

然后 2-3 个线程从上述fprintf()报告了 I/O 错误,例如:

读取错误(描述符:7):输入/输出错误

读取错误(描述符:5):设备的 ioctl 不合适

读取错误(描述符:14):设备的 ioctl 不合适

调试器说,这些线程在多次(5-20)次fread()重复后,在内核的__read_nocancel()中被阻止。所以文件描述符发生了一些非常糟糕的事情。

否则,这有效。管道正确地从ls -R传递数据,它被自定义内置读取。那么危险在哪里呢?为什么在主线程中执行dup()会导致无法fread()读取的内容?我可能会怀疑我是否会在辅助线程中做dup()。但我只将其保存在安全的地方——主线程,然后将准备好的FILE *流传递给辅助线程。也尝试了POSIXopen()read()close(),结果是一样的。

您测试errno不正确。 仅应检查errno设置它的函数是否报告了错误。 标准 C 或 POSIX 库中的任何函数都不会将errno设置为零。 函数可以将errno设置为非零,而不会报告错误。

例如,在 Solaris 上,过去的情况(现在可能仍然如此)是在写入操作之后,errno == ENOTTY文件流是否不是终端(例如,重定向到文件或管道)。 没有问题;输出设备不是终端,因此仅终端操作失败,将errno设置为ENOTTY

您目前拥有:

/* Read e.g. 5 characters, putting them after previous portion */
int count = fread( buf + index, 1, read_size, oconf->stream );
/* Ensure that our whole data is a string - null terminated */
buf[ index + count ] = '';
if ( errno ) {
fprintf( oconf->err, "Read error (descriptor: %d): %sn", fileno( oconf->stream ), strerror( errno ));
}

您需要使用更像以下内容的内容:

int count = fread(buf + index, 1, read_size, oconf->stream);
if (count == 0)
{
/* EOF or error — this might be a time to use feof() or ferror() */
fprintf(oconf->err, "Read error (descriptor: %d): %sn", fileno(oconf->stream), strerror(errno));
…flow control?…
}
else
buf[index + count] = '';

您可能需要在 EOF 和错误路径中提供一些其他控制流详细信息(返回或中断或设置标志);从引用的片段中不清楚什么是合适的。

相关内容

  • 没有找到相关文章

最新更新