【发布时间】:2015-09-11 23:22:17
【问题描述】:
我使用一个用 C++ 编写的插件在 MySQL 上运行查询。它在 Xojo (www.xojo.com) 制作的应用程序中使用。
问题是,如果太多查询过于频繁地执行,它会在 linux 上因分段错误而崩溃。
插件本身的工作原理是在执行查询之前从调用线程中分离出来,以免阻塞主应用程序等,然后在完成后重新连接。我认为重新连接是问题所在(Linux 中的 gdb 调试似乎是这样的)但由于 Xojo 的框架上没有符号,我不太确定。
这是用于分离和重新连接的两种方法/功能
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;
}
我的问题是:上面的代码有什么问题吗?它是否会导致段错误,因为它不小心等等?我不是 C++ 程序员,但在我的理解中似乎太直率,比如不尝试先查看线程是否可用等。再说一次,我不是 C++ 程序员,所以我要说的只是可能是荒谬的等等......
“完整”插件的代码在这里: plugin's source
【问题讨论】:
-
(void * (*)(void))-- 避免类型检查让我害怕。它有多种方法可以搞砸。 -
当然,但这不是我的代码,所以我没事。 :-) 段错误似乎与线程优先级有关。发生的情况是调用此插件方法的线程在协作线程方案中具有最低的优先级。所以,我认为当它试图重新连接时,它会“超时”(?),因为线程需要 太长时间 从睡眠中回来等。我已经提高了线程的优先级在调用该方法之前到最高点,并且超过 24 小时没有更多的 sigfaults(它过去每 10-15 分钟发生一次segfault)
-
尝试“驯服”其他线程可能是明智的。这个问题可能有一天会再次抬头。
标签: c++ mysql linux multithreading plugins