gpt4 book ai didi

C++ 线程附加/分离段错误

转载 作者:IT王子 更新时间:2023-10-29 00:40:37 27 4
gpt4 key购买 nike

我使用一个用 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

最佳答案

代码至少有两个问题:

  1. ReattachCurrentThread()/DetachCurrentThread() 的调用不同步
  2. UnlockDatabaseUsage() 并不总是被调用:函数 MySQLPerformSelect() 可以在不调用 UnlockDatabaseUsage()
  3. 的情况下返回

第一个问题可以解决如下:

#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;
}

关于C++ 线程附加/分离段错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31048888/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com