Can you provide some pseudo code to show how to at least structure it? I am feeling totally lost..
Can you provide some pseudo code to show how to at least structure it? I am feeling totally lost..
The example I referred you to had example code, no?
Cupidvogel (18th April 2015)
Well, you just have to make updateView() a slot and add a matching signal to the QueryFinder class and connect the two.
Then, instead of calling the view directly, you just emit the signal.
Cheers,
_
Okay, I got that part. Here two thread communicate via signals and slots. But in this case, the slot must receive an object of type QueryResult. Qt greatly limits how signals and slots can use parameters, and the one way I can see, is to use a Signal Mapper. But even with Signal Mapper, I don't know how to properly use it to say, emit a signal from one object with a QString as param, and capture and use the sent QString in a slot in another object. I browsed net heavily, I could not find a complete working example of it. Secondly, even Signal Mapper allows only certain basic types of params to be exchanged, like QString. Here the object which is required to update the view is of a custom class, QueryResult. How will the Action class and the View class communicate?
Again, this was a pretty basic example. Which class here should inherit from QThread? I couldn't see any threading in your example at all..
Last edited by Cupidvogel; 18th April 2015 at 11:41.
Yes, I should have written updateView(const QueryResult&), but I thought it would be pretty obvious that the signal would need to transport the data as its argument.
In what way?
Why on earth would you need a signal mapper?
You would not use a signal mapper when you can use a trivial signal/slot connection between two objects.
Heavly for how many seconds?
The first Google hit on signal/slots is the Qt documentation on that topic (which should be the primary source even without search engine help) and it does naturally have an example that transports a value through the connection.
The suggestion was to use moveToThread() of the worker object which does not require subclassing QThread.
Cheers,
_
Cupidvogel (18th April 2015)
Can you give an example of how without using signal mapper I can transport a parameter, say, an object belonging to a custom class?
Which object do I need to move to thread? My Query Action class?
What is it with you and the signal mapper? There is no indication of any need for a signal mapper.
Declare a signal with the respective type as its argument type.
Well, the object that you want to run in the other thread.
Probably the instance of your QueryFinder class.
Cheers,
_
Cupidvogel (18th April 2015)
Look at the Q_DECLARE_METATYPE macro, which you can used to declare any custom types and the qRegisterMetaType macro. These two macros are needed to register a custom metatype that can be used for signal/slot parameters.
The class you moveToThread is the one that has the signals/slots and code that you wish to execute in a separate thread.
Added after 6 minutes:
That is a wildly inaccurate statement. Qt supports all native types, many Qt types, and allows you to register any custom type to the meta object system. How can you say that Qt greatly limits the use of parameters?
Last edited by jefftee; 18th April 2015 at 16:43.
Cupidvogel (18th April 2015)
Cupidvogel (18th April 2015)
Thanks for clarifying. I will usually register my custom types whether or not I am using threads and cross-thread signals/slots. I believe the other beneficial reason to do so is that you can use QVariant for custom types that have been registered, which may come in handy too.
Cupidvogel (18th April 2015)
Okay. First of all, I am very sorry about my statement about signals and slots. I experimented with them, and I can see that they jolly well accept all sorts of parameters, be standard types or custom objects. Sorry about that.
As for the subject of this thread, I tried the example 2.1 of this article: http://blog.debao.me/2013/08/how-to-...ht-way-part-1/
I created a separate WorkerThread class like this:
Qt Code:
//header: WorkerThread.hpp #include <QObject> #include <QThread> #include <QDebug> { Q_OBJECT public: WorkerThread(); private slots: void onTimeout() { } }; //implementation: WorkerThread.cpp #include "WorkerThread.hpp" WorkerThread::WorkerThread() { }To copy to clipboard, switch view to plain text mode
Then in my View class, where I instantiate the action and call its execute method to start the database polling, I added the timer part:
Qt Code:
//view class connect(queryButton, SIGNAL(clicked()), this, SLOT(doQuery())); void QueryView::doQuery() { /*---------------previous code if (!finder) { finder->stop(); } finder = new QueryFinder(this, queryTerm); finder->execute(); -----------------*/ //new code: QThread t; QTimer timer; WorkerThread worker; timer.start(1000); timer.moveToThread(&t); worker.moveToThread(&t); t.start(); }To copy to clipboard, switch view to plain text mode
Now when I click the button, contrary to what is given as output in the example, I get this output:
Qt Code:
From main thread: 0xa06771d4 The program has unexpectedly finished.To copy to clipboard, switch view to plain text mode
followed by the app crashing. The Apple system generated crash report shows this message:
Qt Code:
Thread 0:: Dispatch queue: com.apple.main-thread 0 libsystem_kernel.dylib 0x9a4709cf mach_absolute_time + 1 1 com.apple.HIToolbox 0x9bef7957 GetCurrentEventTime + 18 2 com.apple.HIToolbox 0x9beee570 ReceiveNextEventCommon + 301 3 com.apple.HIToolbox 0x9beee42c _BlockUntilNextEventMatchingListInModeWithFilter + 99 4 com.apple.AppKit 0x95da7721 _DPSNextEvent + 742 5 com.apple.AppKit 0x95da6dc5 -[NSApplication nextEventMatchingMask:untilDate:inMode:dequeue:] + 350 6 com.apple.AppKit 0x95d9b77c -[NSApplication run] + 907 7 libqcocoa.dylib 0x05878bf1 0x5858000 + 134129 10 com.<product_id>.<project> 0x000a2d08 main + 344 11 com.<product_id>.<project> 0x000a1c15 start + 53 Thread 1:: Dispatch queue: com.apple.libdispatch-manager 0 libsystem_kernel.dylib 0x9a4788ce kevent64 + 10 1 libdispatch.dylib 0x953a673f _dispatch_mgr_invoke + 245 2 libdispatch.dylib 0x953a63a2 _dispatch_mgr_thread + 52 Thread 2: 0 libsystem_kernel.dylib 0x9a477e6a __workq_kernreturn + 10 1 libsystem_pthread.dylib 0x904b82b1 _pthread_wqthread + 939 2 libsystem_pthread.dylib 0x904b5e2e start_wqthread + 30 Thread 3: 0 libsystem_kernel.dylib 0x9a477e6a __workq_kernreturn + 10 1 libsystem_pthread.dylib 0x904b82b1 _pthread_wqthread + 939 2 libsystem_pthread.dylib 0x904b5e2e start_wqthread + 30 Thread 4: 0 libsystem_kernel.dylib 0x9a477e6a __workq_kernreturn + 10 1 libsystem_pthread.dylib 0x904b82b1 _pthread_wqthread + 939 2 libsystem_pthread.dylib 0x904b5e2e start_wqthread + 30 Thread 5: 0 libsystem_kernel.dylib 0x9a4719ce mach_msg_trap + 10 1 libsystem_kernel.dylib 0x9a470a70 mach_msg + 68 2 com.apple.CoreFoundation 0x9321bef6 __CFRunLoopServiceMachPort + 214 3 com.apple.CoreFoundation 0x9321b309 __CFRunLoopRun + 1529 4 com.apple.CoreFoundation 0x9321aaa6 CFRunLoopRunSpecific + 390 5 com.apple.CoreFoundation 0x9321a90b CFRunLoopRunInMode + 123 6 com.apple.AppKit 0x95e76ea0 _NSEventThread + 283 7 libsystem_pthread.dylib 0x904b7e13 _pthread_body + 138 8 libsystem_pthread.dylib 0x904b7d89 _pthread_start + 162 9 libsystem_pthread.dylib 0x904b5e52 thread_start + 34 Thread 6:: Qt bearer thread 0 libsystem_kernel.dylib 0x9a47784e __select + 10 1 QtCore 0x02dd9732 qt_safe_select(int, fd_set*, fd_set*, fd_set*, timespec const*) + 546 2 QtCore 0x02dda6ef QEventDispatcherUNIXPrivate::doSelect(QFlags<QEventLoop::ProcessEventsFlag>, timespec*) + 975 3 QtCore 0x02ddb89d QEventDispatcherUNIX::processEvents(QFlags<QEventLoop::ProcessEventsFlag>) + 269 6 QtCore 0x02b9e66c QThreadStorageData::finish(void**) + 3020 7 libsystem_pthread.dylib 0x904b7e13 _pthread_body + 138 8 libsystem_pthread.dylib 0x904b7d89 _pthread_start + 162 9 libsystem_pthread.dylib 0x904b5e52 thread_start + 34 Thread 7:: QProcessManager 0 libsystem_kernel.dylib 0x9a47784e __select + 10 1 QtCore 0x02d2677d QLockFile::unlock() + 2397 2 QtCore 0x02b9e66c QThreadStorageData::finish(void**) + 3020 3 libsystem_pthread.dylib 0x904b7e13 _pthread_body + 138 4 libsystem_pthread.dylib 0x904b7d89 _pthread_start + 162 5 libsystem_pthread.dylib 0x904b5e52 thread_start + 34 Thread 8:: com.apple.CFSocket.private 0 libsystem_kernel.dylib 0x9a47784e __select + 10 1 com.apple.CoreFoundation 0x9326bb3a __CFSocketManager + 906 2 libsystem_pthread.dylib 0x904b7e13 _pthread_body + 138 3 libsystem_pthread.dylib 0x904b7d89 _pthread_start + 162 4 libsystem_pthread.dylib 0x904b5e52 thread_start + 34To copy to clipboard, switch view to plain text mode
What am I doing wrong?
For starters, your QThread instance t will be destroyed right after you do the t.start() because it's allocated on the stack and will go out of scope as sooon as doQuery() returns. Allocate it on the heap (new QThread()) and save a pointer to it for future use or make it a class member variable.
Same for your timer and worker object. Make them member variables or allocate from the heap, etc.
Edit: Not sure why you are trying to move the timer to the thread too. In my experience I have only moved the worker object to the QThread. I would also recommend that you rename your WorkerThread class to WorkerObject as it is misleading to name it as a thread.
Last edited by jefftee; 18th April 2015 at 21:58.
Cupidvogel (18th April 2015)
Cool. That worked. Yes, no need to move the timer, they just gave it by way of an example, in the example following it, they commented that line out.. So along these footsteps, is this design correct for my code? Will this be enough, or am I doing something wrong?
Qt Code:
//inside the slot //get the query term, and pass it to the action, it will update view through signal/slot, so longer need to pass view as param std::shared_ptr<QueryAction> action = std::make_shared<QueryAction>(queryTerm); //this in turn will run a while loop polling the database, and finish gracefully once polling is complete action->execute(); action->moveToThread(t);To copy to clipboard, switch view to plain text mode
Not sure what action->execute() is intended to do in line 8. If your intent is to execute something in the new thread, that's not the correct way to accomplish that. For starters, you haven't created the new QThread yet, nor has it been started (QThread::start). Typically you would emit a signal that is connected to a slot in your Worker object, which can be easily done with a QTimer::singleShot.
The pointer on line 10 is a local pointer, so you will lose the ability to address your QThread after your slot returns. Make the pointer a class member variable, which will allow you to use it later on.
You should also make all of your signal/slot connections for the Worker object and QThread after line 11.
Lastly, after you have created the QThread, moved your Worker object to the QThread, and made your signal/slot connections, you need to start the QThread so that it begins running its event loop.
After you have done all of that, then QTimer::singleShot with a 0ms wait to queue the signal to execute in the new thread, etc.
Once you have all of that working, you should add a boolean to your Worker object that you can use to tell it to stop processing. i.e. You have started doing a long running task in the new thread and the user wants to cancel the task or close the program, etc. Your long running task would then check the boolean to determine if stop has been requested, etc. To make it all thread safe, you should protect the boolean member variable with a QMutex and QMutexLocker whenever you read or change the boolean value.
Hope that helps.
Cupidvogel (18th April 2015)
I don't understand, why do we need a timer here? I though that was an example just for explaining how multi threading works in Qt?
Use a QTimer or don't use a QTimer, doesn't matter to me...
Right, Q_DECLARE_METATYPE is required for encapsulating the type in QVariant. qRegisterMetaType() is needed, if the QVariant needs to be created without calling fromValue().
Which is the case of a signal/slot connection using Qt::QueuedConnection (such as a cross-thread one).
Cheers,
_
Bookmarks