C++;螺纹连接/脱螺纹接头故障 我使用一个用C++编写的插件来运行MySQL查询。它在Xojo(www.Xojo.com)制作的应用程序中使用
问题是,如果执行太多的查询太频繁,它会在linux上崩溃,并出现分段错误 插件本身的工作原理是在执行查询之前从调用线程分离,以避免阻塞主应用程序等,然后在完成后重新连接。我认为这种重新连接是问题所在(linux中的gdb调试似乎是这样),但由于Xojo的框架上没有符号,我不太确定 这是用于分离和重新连接的两种方法/功能C++;螺纹连接/脱螺纹接头故障 我使用一个用C++编写的插件来运行MySQL查询。它在Xojo(www.Xojo.com)制作的应用程序中使用,c++,mysql,linux,multithreading,plugins,C++,Mysql,Linux,Multithreading,Plugins,问题是,如果执行太多的查询太频繁,它会在linux上崩溃,并出现分段错误 插件本身的工作原理是在执行查询之前从调用线程分离,以避免阻塞主应用程序等,然后在完成后重新连接。我认为这种重新连接是问题所在(linux中的gdb调试似乎是这样),但由于Xojo的框架上没有符号,我不太确定 这是用于分离和重新连接的两种方法/功能 void ReattachCurrentThread(void *token) { static void (*pAttachThread)(void*) = nullp
void ReattachCurrentThread(void *token)
{
static void (*pAttachThread)(void*) = nullptr;
if (!pAttachThread)
pAttachThread = (void (*)(void *)) gResolver("_UnsafeAttachCurrentThread");
if (pAttachThread) pAttachThread( token );
}
void * DetachCurrentThread(void)
{
static void * (*pDetachThread)(void) = nullptr;
if (!pDetachThread)
pDetachThread = (void * (*)(void)) gResolver("_UnsafeDetachCurrentThread");
if (pDetachThread) return pDetachThread();
return nullptr;
}
这里有一个地方叫做:
REALdbCursor MySQLPerformSelect(MySQLDatabaseData *db, REALstring queryStr)
{
if (db->fConnection == nullptr) return nullptr;
if (!LockDatabaseUsage( db )) return nullptr;
REALstringData stringData;
if (!REALGetStringData( queryStr, REALGetStringEncoding( queryStr ), &stringData )) return nullptr;
void *detachToken = DetachCurrentThread();
int err = mysql_real_query( db->fConnection, (const char *)stringData.data, stringData.length );
ReattachCurrentThread( detachToken );
db->CaptureLastError();
REALDisposeStringData( &stringData );
REALdbCursor retCursor = nullptr;
if (0 == err) {
// Allocate a cursor
MySQLCursorData *curs = new MySQLCursorData;
bzero( curs, sizeof( MySQLCursorData ) );
curs->fCursor = new MySQLCursor( db );
retCursor = NewDBCursor( curs );
}
UnlockDatabaseUsage( db );
return retCursor;
}
我的问题是:上面的代码是否有任何错误,是否因为不小心而导致segfault等?我不是C++程序员,但我理解得太钝了,比如不想看线程是否可用。等等,我不是C++程序员,所以我所说的可能是荒谬的……
“整个”插件的代码如下:
您确定
DetachCurrentThread()
总是返回指向令牌的指针吗?添加以下检查,看看是否有帮助:
void *detachToken = DetachCurrentThread();
if (detachToken == nullptr) return nullptr; // ensure the pointer to a token is returned before proceeding further.
如果代码仅在运行过多查询时崩溃,则可能需要检查
\u unsafeaturetachcurrentThread
和\u unsafeatetachcurrentThread
,以了解可能导致segfault的争用条件。如果查询太多,可能DetachCurrentThread
会返回一个null ptr?在这种情况下,您可以添加检查detachToken
是否有效
此外,如果
REALGetStringData
失败,可能会出现死锁。返回前请致电解锁DatabaseUsage
。我想您的问题就在这里:
if(db->fConnection==nullptr)返回nullptr代码>
变量db
是一个指针。在评估此情况之前,您需要进行检查:
if (!db)
{
// throw error, return from function call, etc.
}
该代码至少有两个问题:
对ReattachCurrentThread()
/DetachCurrentThread()
的调用不同步
UnlockDatabaseUsage()
并不总是被调用:函数MySQLPerformSelect()
可以在不调用UnlockDatabaseUsage()的情况下返回
第一个问题可以按如下方式解决:
#include <mutex>
std::mutex g_attachmentMutex;
void ReattachCurrentThread(void *token)
{
std::lock_guard<std::mutex> mlg(g_attachmentMutex);
static void (*pAttachThread)(void*) = nullptr;
if (!pAttachThread)
pAttachThread = (void (*)(void *)) gResolver("_UnsafeAttachCurrentThread");
if (pAttachThread) pAttachThread( token );
}
void * DetachCurrentThread(void)
{
std::lock_guard<std::mutex> mlg(g_attachmentMutex);
static void * (*pDetachThread)(void) = nullptr;
if (!pDetachThread)
pDetachThread = (void * (*)(void)) gResolver("_UnsafeDetachCurrentThread");
if (pDetachThread) return pDetachThread();
return nullptr;
}
class MySQLPerformSelectCleaner
{
MySQLDatabaseData *_db;
public:
MySQLPerformSelectCleaner(MySQLDatabaseData *db)
: _db(db)
{
}
~MySQLPerformSelectCleaner()
{
UnlockDatabaseUsage(_db);
}
};
REALdbCursor MySQLPerformSelect(MySQLDatabaseData *db, REALstring queryStr)
{
if (db == nullptr || db->fConnection == nullptr) return nullptr;
if (!LockDatabaseUsage( db )) return nullptr;
MySQLPerformSelectCleaner c(db);
REALstringData stringData;
if (!REALGetStringData( queryStr,
REALGetStringEncoding( queryStr ), &stringData ))
{
return nullptr;
}
void *detachToken = DetachCurrentThread();
// perhaps a check for detachToken==nullptr is needed here
int err = mysql_real_query( db->fConnection, (const char *)stringData.data, stringData.length );
ReattachCurrentThread( detachToken );
db->CaptureLastError();
REALDisposeStringData( &stringData );
REALdbCursor retCursor = nullptr;
if (0 == err) {
// Allocate a cursor
MySQLCursorData *curs = new MySQLCursorData;
bzero( curs, sizeof( MySQLCursorData ) );
curs->fCursor = new MySQLCursor( db );
retCursor = NewDBCursor( curs );
}
// Rely on the cleaner to call this: UnlockDatabaseUsage( db );
return retCursor;
}
是的,它返回调用线程的,所以除非调用应用程序在方法调用和此分离调用之间崩溃,否则它应该始终返回指针等。我想我可能已经找到了解决方案,仍然在检查…(void*(*)(void))
——避免类型检查让我害怕。它有多种方式出错。当然,但这不是我的代码,所以我很好。:-)SEGFULTS似乎与线程优先级有关。发生的情况是,在协作线程方案中,调用此插件方法的线程具有尽可能低的优先级。因此,我认为当它尝试重新连接时,它会“超时”(?),因为线程从睡眠状态返回的时间太长等等。我在调用该方法之前将线程的优先级提高到最高,并且在超过24小时内不再出现SIGFULTS(过去它每10-15分钟进行一次SEGFULT),尝试“驯服”其他线程可能是明智的。有一天,这个问题可能会再次出现。