这个问题与Bad file descriptor有点相似,但完全不同。我知道这是一个“坏问题”(可能是“太局限性了”),但我想不出来,现在已经没有任何想法。
介绍
我有一个管理线程,它启动了75个其他线程。每个线程都做很多事情,所以我只描述相关的事情。
请注意:如果我只启动几个线程——例如3个、5个或10个——就不会出现此错误!这让我认为,这是一些多线程问题,但似乎并不是这样... 在下一节中,您将看到为什么。
因此,在以下2种情况下,有时会出现Bad file descriptor
错误:
情况1
错误出现在TinyXML
中
有一个xml文件,所有线程都需要。所有这些线程都使用TinyXML
解析文件。所有这些线程都只读使用此文件!(我知道这可以优化,但无论如何)。
因此,导致Bad file descriptor
错误的代码如下:
// ...
// NOTE: this is LOCAL, other threads do NOT have access to it
TiXmlDocument doc;
doc.LoadFile( filename );
// and here's the LoadFile:
bool TiXmlDocument::LoadFile( const char* _filename, TiXmlEncoding encoding )
{
//...
FILE* file = fopen( value.c_str (), "rb" );
if ( file )
{
// this IS executed, so file is NOT NULL for sure
bool result = LoadFile( file, encoding );
//...
}
//...
}
bool TiXmlDocument::LoadFile( FILE* file, TiXmlEncoding encoding )
{
// ...
long length = 0;
fseek( file, 0, SEEK_END );
// from the code above, we are SURE that file is NOT NULL, it's valid, but
length = ftell( file ); // RETURNS -1 with errno: 9 (BAD FILE DESCRIPTOR)
// how is this possible, as "file" is not NULL and it appears to be valid?
// ...
}
案例2
这个有点复杂。我已经删除了返回值的检查,但是在我的实际代码中有它们,所以这不是问题。
int hFileR = open( sAlarmFileName.c_str(), O_CREAT | O_RDONLY,
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH );
// hFileR is > 0 for sure, so success
flock( hFileR, LOCK_EX ) /* the result is > 0 for sure, so success*/
// read the file into a string
while( (nRes = read(hFileR, BUFF, MAX_RW_BUFF_SIZE)) > 0 ) // ...
//Write new data to file: reopen/create file - write and truncate mode
int hFileW = open( sAlarmFileName.c_str(),
O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR |
S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH );
// hFileW is > 0 for sure, so success
do
{
int nWrtRes = write( hFileW,
szText + nBytesWritten, nSize - nBytesWritten );
// nWrtRes is always >= 0, so success
nBytesWritten += nWrtRes;
}
while( nSize > nBytesWritten );
close( hFileW ); // this one is successful too
if( flock(hFileR, LOCK_UN) == -1 )
{
// THIS FAILS and executes _Exit( FAILURE );
}
if( close( hFileR ) < 0 )
{
// if the previous one do not fail, this one is successful too
}
抱歉问题有点长,请问您有什么想法吗?
ftell()
之前没有检查fseek()
的返回值。 - WhozCraigFILE *
的两个位置之间,其他一些线程关闭了底层文件描述符。最可能的原因是代码中某处存在双重关闭。 - David Schwartzclose
方法,以此来让那个线程停止。例如,TCP 代码中有一个“读线程”和一个“写线程”,可能会愚蠢地让其他线程调用描述符上的close
方法来使读写线程失败。除了许多可怕的后果之外,如果另一个线程在写线程即将写入时获取相同的描述符,则写线程可能会将敏感数据写入错误的连接。请使用shutdown
方法。 - David Schwartz