It is All about Traffic, and Programming
Search
Archives
0 visitors online now
0 guests, 0 members

Qt

The Move Constructor: A Linking Pitfall of Qt Library with Different Compilers

Move constructor is a C++11 feature from ISO/IEC14882:2011.  It enhanced the old-school C++ copy constructor by moving the resource of an object, instead of member-wise copying.  It is faster than a copy constructor.  Thus a C++11 compiler will generate six special member functions for a C++ object, including  move constructor and move assignment operator:

  • Default Constructor
  • Copy Constructor
  • Copy Assignment Operator
  • Destructor
  • Move Constructor
  • Move Assignment Operator

We are not going to discuss C++11 Move Constructor in details here –  better details and better explanations are there, and there.

The motivation of  this article,  is not to discuss the semantics or usage of Move Constructor,  but an interesting debugging experience, and the lessons learned which involves C++11 move constructor.

Long story short – I have been working on developing an advanced Qt-based C++ plugin DLL for a host software developed in Qt 4.8.7.   I was using Visual C++ 2010 compiler, and the Qt for VS2010 official release for commercial applications.

The plugin DLL is supposed to be dynamically loaded by the host via Qt’s QLibrary API (see my previous article on this subject), which internally will call Microsoft’s Win32 API LoadLibrary.  Somehow, I got the following error, when trying to load the DLL into the host software:

34f8:3518 @ 01570140 – LdrpGetProcedureAddress – INFO: Locating procedure “AcdssPluginFactory” by name
34f8:3518 @ 01570140 – LdrpNameToOrdinal – WARNING: Procedure “AcdssPluginFactory” could not be located in DLL at base 0x0B630000
34f8:3518 @ 01570140 – LdrpReportError – WARNING: Locating export “AcdssPluginFactory” for DLL “Unknown” failed with status: 0xc0000139
34f8:1168 @ 01570265 – LdrpReportError – ERROR: Locating export “??4QString@@QAEAAV0@$$QAV0@@Z” for DLL “C:\Program Files (x86)\…\plugins\acdssplugin.DLL” failed with status: 0xc0000139

The above debug messages were generated by GFlags Utility, which comes with Debugging Tools for Windows. You can find the most advanced debugging techniques including how to use GFlags utility from the excellent book Inside Windows Debugging.  In our case, we just need to set “Show Loader Snaps” flag, as shown in the figure.  This is a typical way of debugging LoadLibrary failures.

2016-10-12_21-41-26

Looking at the debug messages, it is simply pointing out that LoadLibrary fails because an exported function is missing from the image space – its C++ mangled name as  “??4QString@@QAEAAV0@$$QAV0@@Z”,  which can be interpreted as:


    ? = C++ mangled symbol
    ?4 = "operator="
    QString@ = the enclosing class, hence method name: QString::operator=
    @ = end of the scope
    Q = public
    A = no const and volatile qualifier
    E = __thiscall
    AAV0 = const ref to the first named class (QString) - the return value (const QString &)
    @ = end return type
    $$ = move constructor &&
    QAV0 = const pointer to first named class - QString * const
    @ = end parameter type
    @ = end parameters
    Z = function

So clearly, the host software was complaining that the Move Constructor of QString can not be located in any of the image space.  Upon further inspection of the host software, it is discovered it was compiled using VS2005.  QtCore4.dll does not have the Move Constructor generated with VC++ 2005 compiler.  

The solution is simple – just rebuilt the Qt 4.8.7 using VC++ 2005, and rebuilt the plugin DLL.  Above all, the lessons learned are:

Do NOT mix Qt library compiled with different compilers, EVEN with the same Qt Version.  Period.

QThread: the Way of Do-It-Right

Recently I run into this blog of Bradley T. Hughes, a member of the Qt development team.   He put an interesting post about the “right” way of using QThread.  That is,  to sub-class QObject and use  moveToThread.  This is quite contrary to what is said in the existing Qt official documentation, which suggests subclassing QThread directly.

The reason of doing this is that QThread should be treated as an interface,  a control point or a manager of worker threads.  As such  it shouldn’t contain  any threaded code.   As a matter of fact,  QThread’s thread affinity by default is with its creating thread,  not the thread it spawns.  This means QThread by default shares the same thread message queue as its creating thread, which in most cases is the main thread.

There are a few discussions on the internet about subclassing QThread,  while calling moveToThread in the QThread sub-class’s constructor.  This is based on the misconception of QThread usage.  Sometimes it works as a work-around trick to change the default thread affinity from the creating thread to the thread it spawns.  This practice is not encouraged,  according to Bradley blog, because this  will result in not only a bad design violating OO principles but also problems very hard to debug later.  This is well explained in Bradley’s blog.

Here is a brief summary of the right (suggested) way of using QThread:

1. When no event-loop is involved,  we can continue with the “official” approach, like what is introduced in the Qt documentation, i.e.,

  • Subclass QThread;
  • Overload Run();
  • Use some termination token inside a while loop inside Run(), so it can exit gracefully.

2. When event-loop is involved, things are a little more complicated:

  • Subclass QObject, define relevant signals and slots.  Distribute the “threaded” code over the relevant slots;
  • Since QThread::run() automatically calls  QThread::exec() so no need to worry that (for Qt 4.4 and later);
  • Call QObject::moveToThead, so that the slots are executed in the context of the working threads spawned and managed by the QThread instance.

Maya Posch’s blog gives a nice example illustrating the the above:

class Worker : public QObject
{
    Q_OBJECT
public:
    Worker();
    ~Worker();
public slots:
    void process();
signals:
    void finished();
    void error(QString err);
private:
    // add your variables here
};

// --- CONSTRUCTOR ---
Worker::Worker()
{
   // you could copy data from constructor arguments to internal variables here.
}

// --- DECONSTRUCTOR ---
Worker::~Worker()
{
   // free resources
}

// --- PROCESS ---
// Start processing data.
void Worker::process()
{
   // allocate resources using new here
   qDebug("Hello World!");
   emit finished();
}

In Maya’s original example,  the following is posted:

QThread* thread = new QThread;
Worker* worker = new Worker();

worker->moveToThread(thread);

connect(worker, SIGNAL(error(QString)), this, SLOT(errorString(QString)));
connect(thread, SIGNAL(started()), worker, SLOT(process()));
connect(worker, SIGNAL(finished()), thread, SLOT(quit()));
connect(worker, SIGNAL(finished()), worker, SLOT(deleteLater()));

// The following line may cause memory leak.
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
thread->start();

There are some nuances here –

First,  the highlighted line may cause leak of the worker instance,  because the the QThread instance may have already be deleted earlier. Then the thread context is no long existing for the following line of code since it is only executed in the context of the thread managed by QThread:

connect(worker, SIGNAL(finished()), worker, SLOT(deleteLater()));

Therefore,  this line

connect(thead, SIGNAL(finished()), thread, SLOT(deleteLater()));

should be changed to

connect(worker, SIGNAL(destroyed()), thread, SLOT(deleteLater()));

Second,  do NOT allocate resources in the ctor of QOjbect derived class.  This is because before calling moveToThread,  the thread affinity is still with the main thread (i.e., the thread where the instance of the derived class is created) hence it may cause some hidden hard-to-debug problems later with the switch of thread affinity.

REFERENCE LINKS 

  1. http://labs.qt.nokia.com/2010/06/17/youre-doing-it-wrong/
  2. http://labs.qt.nokia.com/blogs/2006/12/04/threading-without-the-headache/
  3. http://labs.qt.nokia.com/blogs/2007/07/05/qthreads-no-longer-abstract/
  4. http://gitorious.org/qthreadhowto/qthreadhowto/trees/master
  5. http://blog.exys.org/entries/2010/QThread_affinity.html
  6. http://thesmithfam.org/blog/2010/02/07/talking-to-qt-threads/
  7. http://mayaposch.wordpress.com/2011/11/01/how-to-really-truly-use-qthreads-the-full-explanation/
  8. http://hi.baidu.com/cyclone/blog/item/5fac3bc7ab1b90d1d10060f2.html

Using Delphi DLL with C++

Delphi has  good support for database applications.  Recently I have been  working on a scientific application in C++/Qt – the data access part of this application was  implemented as a Delphi DLL .

In order to use a Delphi DLL with a C++ host, there are a few options:

  1. Generate proper import lib  by defining your own def file, see this post
  2. Convert Delphi DLL to static lib using this tool
  3. Or dynamically loading the DLL at run time.  For that,  you’ll  have to do the following tedious steps(excerpted from MSDN):
// Define the function prototypes
 typedef short (CALLBACK* FindArtistType)(LPCTSTR);
// Load the DLL using the LoadLibrary function, and keep 
// the handle to the DLL instance.  
dllHandle = LoadLibrary("art.dll");
// Get a pointer to each function using the GetProcAddress 
// function. Cast function pointers to the types defined in the
// first step. 
FindArtistPtr = (FindArtistType)GetProcAddress(dllHandle,
"FindArtist");
// Verify function pointers, and use the fuctions
if (runTimeLinkSuccess = (NULL != FindArtistPtr))
   short retVal = FindArtistPtr(myArtist);
// Unload the DLL.
freeResult = FreeLibrary(dllHandle);
Qt provides a very nice class, QLibrary to streamline the above procedures, and the nice thing is, the instance is ref counted, hence the DLL won’t be unloaded unless all QLibrary instances go out of scope. The following is the sample code that loads the dll  developed in Delphi. Isn’t that nice?