7

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?

Community
  • 1
  • 1
Ruslan
  • 18,162
  • 8
  • 67
  • 136

2 Answers2

9

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.

zakinster
  • 10,508
  • 1
  • 41
  • 52
  • This seems to only be true for new enough Qt versions. I don't see behavior cited by @Marek in 4.8.1. Instead all my threads have the name coinciding with name of binary. Also, `grep` for `setCurrentThreadName` doesn't find anything in the distro-supplied source tree. Anyway, seems this is the first real support of this in Qt, so I'll accept your answer. – Ruslan Nov 08 '13 at 17:29
  • @Ruslan Yes, as you can see [here](https://qt.gitorious.org/qt/qt/commit/aa21fcac3672cc6f0dca064b34bbe02ca4f4def7), that feature was implemented for debugging purpose. I'm actually surprised that it's referenced in the Qt documentation since it's not much more than a debugging workaround. – zakinster Nov 08 '13 at 17:39
7

In Qt documentation you can find:

To choose the name that your thread will be given (as identified by the command ps -L on Linux, for example), you can call setObjectName() before starting the thread. If you don't call setObjectName(), the name given to your thread will be the class name of the runtime type of your thread object (for example, "RenderThread" in the case of the Mandelbrot Example, as that is the name of the QThread subclass). Note that this is currently not available with release builds on Windows.

Marek R
  • 32,568
  • 6
  • 55
  • 140