我写了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 ] = '\0';
if ( errno ) {
fprintf( oconf->err, "Read error (descriptor: %d): %s\n", 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 *流传递给二级线程。在POSIX open()、read()和close()上也进行了尝试,结果是相同的。
发布于 2017-02-12 16:25:31
您正在错误地测试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 ] = '\0';
if ( errno ) {
fprintf( oconf->err, "Read error (descriptor: %d): %s\n", 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): %s\n", fileno(oconf->stream), strerror(errno));
…flow control?…
}
else
buf[index + count] = '\0';在EOF和错误路径中,您可能需要一些其他的控制流细节(返回、中断或设置标志);从引用的片段中不清楚什么是合适的。
https://stackoverflow.com/questions/42188546
复制相似问题