PDA

View Full Version : Calling QThread::currentThread from within boost::thread returns inconsistent results



donelron
27th August 2015, 12:20
Dear all,

I am working with legacy code which uses a Qt-GUI and some boost-based libraries. The application spawns some QThreads and these QThreads spawn bost::threads.
For logging and debugging purposes I need to get the QThread IDs as well as the boost::thread IDs.
I have written the following minimal working example to show in a more detailed fashion, what I need to do:



#include <QThread>
#include <boost/thread.hpp>
#include <boost/thread/thread.hpp>

class mySynchronousClass
{
public:
mySynchronousClass(std::string strFlag){
if (strFlag=="Qt"){
std::cout << "QThreadID (called from mySynchronousClass) is " << QThread::currentThread() << std::endl;
}
else if (strFlag=="boost"){
std::cout << "boost::thread ID (called from mySynchronousClass) is " << boost::this_thread::get_id() << std::endl;
}
}
};

class myTestWorker{
public:
myTestWorker(){}
void DoWork() {
std::cout << std::endl << "Start of myTestWorker::DoWork ------------------------" << std::endl;
std::cout << "QThreadID is " << QThread::currentThread() << std::endl;
std::cout << "boost::thread ID is " << boost::this_thread::get_id() << std::endl;
mySynchronousClass testSyncClass3("Qt");
mySynchronousClass testSyncClass4("boost");
std::cout << "End of myTestWorker::DoWork ------------------------" << std::endl << std::endl;
}
};


class myQThread : public QThread
{
Q_OBJECT
public:
myQThread() {
std::cout << "QThreadID is " << QThread::currentThread() << std::endl;

mySynchronousClass testSyncClass("Qt");

myTestWorker w1;
boost::thread BoostWorkerThread1(&myTestWorker::DoWork, &w1);
BoostWorkerThread1.join();
mySynchronousClass testSyncClass2("Qt");
}
~myQThread(){ }

void run(){
//do sth .....
}
};


int main(int argc, char *argv[])
{
myQThread testThread;
testThread.start();

system("pause");
}


This gives the following output:


QThreadID is 0000000000274850
QThreadID (called from mySynchronousClass) is 0000000000274850

Start of myTestWorker::DoWork ------------------------
QThreadID is 000000000029CC20
boost::thread ID is 23bc
QThreadID (called from mySynchronousClass) is 000000000029CC20
boost::thread ID (called from mySynchronousClass) is 23bc
End of myTestWorker::DoWork ------------------------

QThreadID (called from mySynchronousClass) is 0000000000274850



Apparently, QThread::currentThread() returns a consistent unique thread ID (in this case: 0000000000274850) as long as it is NOT called from within a boost::thread. If called from within a boost::thread the ID which is returned is changed (in this case to 000000000029CC20).
Is it possible get a consistent QThread ID, even if called from within a boost::thread?
A consistent QThread ID would then be (with my example from above):


QThreadID is 0000000000274850
QThreadID (called from mySynchronousClass) is 0000000000274850

Start of myTestWorker::DoWork ------------------------
QThreadID is 0000000000274850
boost::thread ID is 23bc
QThreadID (called from mySynchronousClass) is 0000000000274850
boost::thread ID (called from mySynchronousClass) is 23bc
End of myTestWorker::DoWork ------------------------

QThreadID (called from mySynchronousClass) is 0000000000274850

If it is possible, how do I do it???

Many thanks in advance and best regards

By the way, I am using Visual Studio 11 (2012) on Windows7

anda_skoa
27th August 2015, 19:15
DoWork() is not executed in the context of a QThread, especially not in the context of the already existing thread.
Why would QThread::currentThread() return the same value as an existing QThread if the current thread is not that one?

Btw, currentThread() doesn't have any meaning out of the context of a QThread, since there is no QThread object wrapping the current system thread.
Have you tried QThread::currentThreadId()?

Cheers,
_

donelron
28th August 2015, 10:28
Thanks for the quick reply!

DoWork() is not executed in the context of a QThread, especially not in the context of the already existing thread.
You are right, I should have put the call to myTestWorker::DoWork into the run method of myQThread instead of the constructor of myQThread. I corrected this mistake.

With regard to QThread::currentThreadId() the Qt documentation says:
"Returns the thread handle of the currently executing thread.
Warning: The handle returned by this function is used for internal purposes and should not be used in any application code."
Therefore I was assuming that QThread::currentThreadId() is not what I want here.

With the following code (myTestWorker::DoWork moved into the run method of myQThread) my output now looks like (see below):


class mySynchronousClass
{
public:
mySynchronousClass(std::string strFlag){
if (strFlag=="Qt"){
std::cout << "QThread::currentThreadId() (called from mySynchronousClass) returns " << QThread::currentThreadId() << std::endl;
std::cout << "QThread::currentThread() (called from mySynchronousClass) returns " << QThread::currentThread() << std::endl;
}
else if (strFlag=="boost"){
std::cout << "boost::thread ID (called from mySynchronousClass) is " << boost::this_thread::get_id() << std::endl;
}
}
};

class myTestWorker{
public:
myTestWorker(){}
void DoWork() {
std::cout << std::endl << "Start of myTestWorker::DoWork ------------------------" << std::endl;
std::cout << "QThread::currentThreadId() returns " << QThread::currentThreadId() << std::endl;
std::cout << "QThread::currentThread() returns " << QThread::currentThread() << std::endl;
std::cout << "boost::thread ID is " << boost::this_thread::get_id() << std::endl;
mySynchronousClass testSyncClass3("Qt");
mySynchronousClass testSyncClass4("boost");
std::cout << "End of myTestWorker::DoWork ------------------------" << std::endl << std::endl;
}
};


class myQThread : public QThread
{
Q_OBJECT
public:
myQThread() {}
~myQThread(){ }

void run(){
std::cout << "QThread::currentThreadId() returns " << QThread::currentThreadId() << std::endl;
std::cout << "QThread::currentThread() returns " << QThread::currentThread() << std::endl;

mySynchronousClass testSyncClass("Qt");

myTestWorker w1;
boost::thread BoostWorkerThread1(&myTestWorker::DoWork, &w1);
BoostWorkerThread1.join();
mySynchronousClass testSyncClass2("Qt");
}
};



int main(int argc, char *argv[])
{
QApplication app(argc, argv);
myQThread testThread;
testThread.start();

return app.exec();
}




QThread::currentThreadId() returns 00000000000025C8
QThread::currentThread() returns 000000000026FE68
QThread::currentThreadId() (called from mySynchronousClass) returns 00000000000025C8
QThread::currentThread() (called from mySynchronousClass) returns 000000000026FE68

Start of myTestWorker::DoWork ------------------------
QThread::currentThreadId() returns 0000000000001CA4
QThread::currentThread() returns 00000000003AD010
boost::thread ID is 1ca4
QThread::currentThreadId() (called from mySynchronousClass) returns 0000000000001CA4
QThread::currentThread() (called from mySynchronousClass) returns 00000000003AD010
boost::thread ID (called from mySynchronousClass) is 1ca4
End of myTestWorker::DoWork ------------------------

QThread::currentThreadId() (called from mySynchronousClass) returns 00000000000025C8
QThread::currentThread() (called from mySynchronousClass) returns 000000000026FE68




Within myTestWorker::DoWork both the ID for the boost::thread and the QThread are now 1ca4, which probably makes sense, since according to the Qt documentation
"On Windows ... this function [i. e.QThread::currentThreadId()] returns the DWORD (Windows-Thread ID)".
So, neither QThread::currentThreadId(), nor QThread::currentThread() can provide consistent thread IDs for myQThread.
Does anybody have an idea how I could solve this?

anda_skoa
28th August 2015, 15:48
Therefore I was assuming that QThread::currentThreadId() is not what I want here.

You are only using it for logging, so you should be fine.


So, neither QThread::currentThreadId(), nor QThread::currentThread() can provide consistent thread IDs for myQThread.

I am not sure what you mean. You write

Within myTestWorker::DoWork both the ID for the boost::thread and the QThread are now 1ca4

Same value for the same thread sounds quite consistent to me.

Cheers,
_

donelron
1st September 2015, 09:17
Same value for the same thread sounds quite consistent to me
I was aiming for some mechanism/function that would consistently put out the same QThreadID, no matter where this function is called.
E. g. if I call it from within a boost::thread which is "encapsulated" into a QThread then the QThread-ID is identical to the QThread-ID I receive when I call it before the boost::thread started.
I manually edited my output so it looks like what I want it to look like:



QThreadId is 00000000000025C8
Start of myTestWorker::DoWork ------------------------
QThreadId is 00000000000025C8
boost::thread ID is 1ca4
End of myTestWorker::DoWork ------------------------
QThreadId is 00000000000025C8

In contrast to what I previously posted, QThreadId has always the same (consistent) value, i. e. 25C8. No matter, if we are inside the boost::thread or not.

anda_skoa
1st September 2015, 10:05
I was aiming for some mechanism/function that would consistently put out the same QThreadID, no matter where this function is called.

Well, obviously it matters which thread executes the function.
The same thread has the same thread ID wherever it goes.
A different thread has a different thread ID, it is not the same thread.



E. g. if I call it from within a boost::thread which is "encapsulated" into a QThread then the QThread-ID is identical to the QThread-ID I receive when I call it before the boost::thread started.

There is no such thing as one thread being "encapsulated" in another. All threads run in parallel, each on its own.


I manually edited my output so it looks like what I want it to look like:



In contrast to what I previously posted, QThreadId has always the same (consistent) value, i. e. 25C8.

Exactly.
The same thread always has the same ID.



No matter, if we are inside the boost::thread or not.
Right, the code will execute regardless of what kind of thread executes it.

Obviously the output will be different for different threads, after all "ID" is a short hand for "identifier".
Two threads having the same identifier would be weird.

Cheers,
_

donelron
4th September 2015, 08:56
Thanks for taking so much time to explain!