Search code examples
multithreadingqtportability

Is there a portable way to give thread name with Qt?


I know I can set thread name (the one visible in gdb and htop) in Linux using prctl(). But with another OSes this most likely won't work. Also, I could try using pthread_setname_np(), which is a bit more available across POSIX systems, but still lacks full compatibility.

So I'd like to have some more portable way, maybe something QThread provides which I've not found. Is there any such way?


Solution

  • There's nothing in the QThread API to manually manage the system name of the thread, however, since version 4.8.3, Qt will automatically set the name of your thread to the name of the thread object (QObject::objectName()).

    This is handled in the implementations of QThread as described below.

    You have something like this in qthread_unix.cpp:

    #if (defined(Q_OS_LINUX) || defined(Q_OS_MAC) || defined(Q_OS_QNX))
    static void setCurrentThreadName(pthread_t threadId, const char *name)
    {
    #  if defined(Q_OS_LINUX) && !defined(QT_LINUXBASE)
        Q_UNUSED(threadId);
        prctl(PR_SET_NAME, (unsigned long)name, 0, 0, 0);
    #  elif defined(Q_OS_MAC)
        Q_UNUSED(threadId);
        pthread_setname_np(name);
    #  elif defined(Q_OS_QNX)
        pthread_setname_np(threadId, name);
    #  endif
    }
    #endif
    
    /* 
     * [...]
     */
    
    QString objectName = thr->objectName();
    
    if (Q_LIKELY(objectName.isEmpty()))
        setCurrentThreadName(thr->d_func()->thread_id, thr->metaObject()->className());
    else
        setCurrentThreadName(thr->d_func()->thread_id, objectName.toLocal8Bit());
    

    And the equivalent in qthread_win.cpp:

    typedef struct tagTHREADNAME_INFO
    {
        DWORD dwType;      // must be 0x1000
        LPCSTR szName;     // pointer to name (in user addr space)
        HANDLE dwThreadID; // thread ID (-1=caller thread)
        DWORD dwFlags;     // reserved for future use, must be zero
    } THREADNAME_INFO;
    
    void qt_set_thread_name(HANDLE threadId, LPCSTR threadName)
    {
        THREADNAME_INFO info;
        info.dwType = 0x1000;
        info.szName = threadName;
        info.dwThreadID = threadId;
        info.dwFlags = 0;
    
        __try
        {
            RaiseException(0x406D1388, 0, sizeof(info)/sizeof(DWORD), (const ULONG_PTR*)&info);
        }
        __except (EXCEPTION_CONTINUE_EXECUTION)
        {
        }
    }
    
    /* 
     * [...]
     */
    
    QByteArray objectName = thr->objectName().toLocal8Bit();
    qt_set_thread_name((HANDLE)-1, objectName.isEmpty() ? thr->metaObject()->className() : objectName.constData());
    

    Note that on Windows, the above code won't be executed if QT_NO_DEBUG is set, thus it won't work in Release mode.