C++;螺纹连接/脱螺纹接头故障 我使用一个用C++编写的插件来运行MySQL查询。它在Xojo(www.Xojo.com)制作的应用程序中使用

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

问题是,如果执行太多的查询太频繁,它会在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;
}
我的问题是:上面的代码是否有任何错误,是否因为不小心而导致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),尝试“驯服”其他线程可能是明智的。有一天,这个问题可能会再次出现。