My code is a plugin of a host software which gets limited processing time. Therefore, I create a second thread (via system API) and start QApplication there. That way, the GUI runs smoothly.
Now, I would like to run a QThread event loop in the original such that I could use Signal/Slot (Qt::QueuedConnection) to invoke functions that are not thread safe in the host software.
Is there a way to create such QThread event loop without creating a new thread?
Thanks!
I'm not quit sure if i get you right,
but you can start your own event loop just by calling QEventLoop::exec() on a e.g. private class member.
Don't forget to call QEventLoop.exit().
Bye, Lars
Related
I am trying to use boost::asio async client example with a simple Qt GUI like:
A little snippet from my app:
The button click SLOT:
void RestWidget::restGetCall()
{
networkService ntwkSer("www.boost.org","80");
connect(&ntwkSer, SIGNAL(responseReady(std::string)), this, SLOT(showResponse(std::string)));
ntwkSer.get("/LICENSE_1_0.txt");
}
The networkService class is just a wrapper of the above linked boost sample code.Its derived from QObject class for signal,slot mechanism.
void networkService::get(const std::string & path)
{
// boost::thread (boost::bind(&networkService::networkCall,this,path));//this gives me sigabrt
networkCall(path);//this works fine, and i get output as pictured above.
}
void networkService::networkCall(const std::string path)
{
tcp::resolver::query query(host_, port_);//also these host,port fields come out to be invalid/garbage.
//tcp::resolver::query query("www.boost.org","80");//still doesnt resolve the SIGABRT
resolver_.async_resolve(query,
boost::bind(&networkService::handle_resolve, this,
boost::asio::placeholders::error,
boost::asio::placeholders::iterator,
path));
io_service.run();
}
The problem, is when i run the io_service.run() from the boost::thread. i get SIGABRT.
also he host_,port_ networkService wrapper class fields inside the networkService::networkCall(path) function on debugging come out to be invalid, which get saved while constructing:
networkService ntwkSer("www.boost.org","80");
The obvious reason for boost::thread is to make GUI non-blocking,since io_service() has its own eventloop. My intention is to run boost::asio async calls in a seperate boost thread, and notify the GUI thread with QT's Q_OBJECT signal slot mechanism.
I don't get the reason of SIGABRT and also why could the field values of host_ and port_ become invalid once i start using boost::thread.
PS: This same setup, behaves correctly with boost::thread from a similar commandline application (no Qt GUI code), i.e when the networkService class is not hacked for Qt signal/slot to notify the main GUI thread. Here, i use the boost::asio's response from within the boost::thread.
Edit:
as per responses to my question, i tried this... i disabled Q_OBJECT signal/slot and QObject derivation of the networkservice class, to be sure MOC isnt messing things up.. but still, the issue prevails, i get access violation on windows vs sigabrt on linux. The issue of the networkservice object's fields getting corrupted is also present, eventually getting access violation.
In effect no change in behaviour.
before launching thread:
from inside thread
access violation on continue...
So, even without MOC , the issue is still there.
Edit 2:
Im sorry for bothering.. i did a huge mistake, of using a local networkService object from within the boost::thread, which got scoped out when the thread actually ran!
It's difficult to get the asio io_service.run() function to "play well" with the Qt event loop.
It's easier to use a Qt slot that calls io_service::poll() or io_service::poll_one() and then connect that slot to a QTimerEvent.
And it's even easier to use QNetworkAccessManager instead of asio see Qt Client Example
The problem is that with qt only one thread is allowed to manipulate the gui in qt. That is the one calling QApplication::exec. This is done to remove complexity for the users of qt and due to that QApplication / message loop being a singleton. That being said there is some magic going on in qt with threads. All QObjects are assigned a thread. By default the one on which they are created. When a signal slot connection is made it is determined how to actually dispatch the call. If the objects belong to the same thread a signal is dispatched by directly / synchronous invoking the slot. If the objects are assigned to distinguished threads a message is send from one thread to another to invoke the slot on the thread that is assigned to the object where the slot lives. This is what you actually need here.
The problem with your code is that both of your QObjects are created on the same thread. They are therefore assigned the same thread. So the slot which manipulates the GUI is called directly from your worker thread and remember this is prohibited! Since your worker is not the one calling QApplication::exec. To override the automatics and convince to correctly do the thread switch when calling the slot you must use Qt::QueuedConnection when doing the connect.
connect(&ntwkSer, SIGNAL(responseReady(std::string)), this, SLOT(showResponse(std::string)), Qt::QueuedConnection);
I have the same situation like this: stop thread started by qtconcurrent::run
I need to close child thread (started with QtConcurrent::run) on closeEvent in QMainWindow.
But my function in child thread use code from *.dll: I can`t use loop because all that I do - is calling the external dll like
QFuture<void> = QtConcurrent::run(obj->useDllfunc_with_longTermJob());
And when I close the app with x-button my gui is closed, but second thread with_longTermJob() still worked and when is finished I have an error.
I know some decisions for this:
using other functions like map() or something else with
QFuture.cancel/stop functionality, not QtConcurrent::run().But I need only one function call. run() is what I need.
or use QThread instead Concurrent.But it`s not good for me.
What method more simple and better and how can I implement this? Is there a method that I don`t listed?
Could you provide small code sample for decision. Thx!
QtConcurrent::run isn't a problem here. You must have means of stopping the dllFuncWithLongTermJob. If you don't have such means, then the API you're using is broken, and you're out of luck. There's nothing you can do that'd be generally safe. Forcibly terminating a thread can leave the heap in an inconsistent state, etc. - if you need to terminate a thread, you need to immediately abort the application.
Hopefully, you can call something like stopLongTermJob that sets some flag that interrupts the dllFuncWithLongTermJob.
Then:
auto obj = new Worker;
auto objFuture = QtConcurrent::run([=]{obj->dllFuncWithLongTermJob();});
To interrupt:
obj->stopLongTermJob(); // must be thread-safe, sets a flag
objFuture.waitForFinished();
I am using NSURLSession dataTaskWithURL:completionHandler. It looks like completionHandler is executed in a thread which is different than the thread(in my case, it's the main thread) which calls dataTaskWithURL. So my question is, since it is asynchronized, is it possible that the main thread exit, but the completionHandler thread is still running since the response has not come back, which is the case I am trying to avoid. If this could happen, how should I solve the problem? BTW, I am building this as a framework, not an application.Thanks.
In the first part of your question you seem un-sure that the completion handler is running on a different thread. To confirm this let's look at the NSURLSession Class Reference. If we look at the "Creating a Session" section we can see in the description for the following method the answer.
+ sessionWithConfiguration:delegate:delegateQueue:
Swift
init(configuration configuration: NSURLSessionConfiguration,
delegate delegate: NSURLSessionDelegate?,
delegateQueue queue: NSOperationQueue?)
Objective-C
+ (NSURLSession *)sessionWithConfiguration:(NSURLSessionConfiguration *)configuration
delegate:(id<NSURLSessionDelegate>)delegate
delegateQueue:(NSOperationQueue *)queue
In the parameters table for the NSOperationQueue queue parameter is the following quote.
An operation queue for scheduling the delegate calls and completion handlers. The queue need not be a serial queue. If nil, the session creates a serial operation queue for performing all delegate method calls and completion handler calls.
So we can see the default behavior is to provide a queue whether from the developer or as the default class behavior. Again we can see this in the comments for the method + sessionWithConfiguration:
Discussion
Calling this method is equivalent to calling
sessionWithConfiguration:delegate:delegateQueue: with a nil delegate
and queue.
If you would like a more information you should read Apple's Concurrency Programming Guide. This is also useful in understanding Apple's approach to threading in general.
So the completion handler from - dataTaskWithURL:completionHandler: is running on a different queue, with queues normally providing their own thread(s). This leads the main component of your question. Can the main thread exit, while the completion handler is still running?
The concise answer is no, but why?
To answer this answer this we again turn to Apple's documentation, to a document that everyone should read early in their app developer career!
The App Programming Guide
The Main Run Loop
An app’s main run loop processes all user-related events. The
UIApplication object sets up the main run loop at launch time and uses
it to process events and handle updates to view-based interfaces. As
the name suggests, the main run loop executes on the app’s main
thread. This behavior ensures that user-related events are processed
serially in the order in which they were received.
All of the user interact happens on the main thread - no main thread, no main run loop, no app! So the possible condition you question mentions should never exist!
Apple seems more concerned with you doing background work on the main thread. Checkout the section "Move Work off the Main Thread"...
Be sure to limit the type of work you do on the main thread of your
app. The main thread is where your app handles touch events and other
user input. To ensure that your app is always responsive to the user,
you should never use the main thread to perform long-running or
potentially unbounded tasks, such as tasks that access the network.
Instead, you should always move those tasks onto background threads.
The preferred way to do so is to use Grand Central Dispatch (GCD) or
NSOperation objects to perform tasks asynchronously.
I know this answer is long winded, but I felt the need to offer insight and detail in answering your question - "the why" is just as important and it was good review :)
NSURLSessionTasks always run in background by default that's why we have completion handler which can be used when we get response from Web service.
If you don't get any response explore your request URL and whether HTTPHeaderFields are set properly.
Paste your code so that we can help it
I just asked the same question. Then figured out the answer. The thread of the completion handler is setup in the init of the NSURLSession.
From the documentation:
init(configuration configuration: NSURLSessionConfiguration,
delegate delegate: NSURLSessionDelegate?,
delegateQueue queue: NSOperationQueue?)`
queue - A queue for scheduling the delegate calls and completion handlers. If nil, the session creates a serial operation queue for performing all delegate method calls and completion handler calls.*
My code that sets up for completion on main thread:
var session = NSURLSession(configuration: configuration, delegate:nil, delegateQueue:NSOperationQueue.mainQueue())
(Shown in Swift, Objective-C the same) Maybe post more code if this does not solve.
I am new to qt.
I have an application with one thread that uses libevent loop. I wanted to add another network thread that sends out jobs as post requests via QNetworkAccessManager.
How can i implemet it?
Suppose ,
1. i have Obj that inherts QOBject (Inside i have QnetworkAccessmanager that sends requests)
2. My Thread class that inherits QThread and reimplements run method with its event loop
I wanted to send new jobs(requests) to the event loop of this MyThread how do i do that?
Thanks in advance for answering.
According to http://doc.qt.io/qt-5/qpointer.html, QPointer is very useful. But I found it could be inefficient in the following context:
If I want to show label for three times or do something else, I have to use
if(label) label->show1();
if(label) label->show2();
if(label) label->show3();
instead of
if(label) { label->show1();label->show2();label->show3(); }
just because label might be destroyed in another thread after label->show1(); or label->show2();.
Is there a beautiful way other than three ifs to get the same functionality?
Another question is, when label is destroyed after if(label), is if(label) label->show1(); still wrong?
I don't have experience in multi-threaded programs. Any help is appreciated. ;)
I think the only safe way to do it is to make sure you only access your QWidgets from within the main/GUI thread (that is, the thread that is running Qt's event loop, inside QApplication::exec()).
If you have code that is running within a different thread, and that code wants the QLabels to be shown/hidden/whatever, then that code needs to create a QEvent object (or a subclass thereof) and call qApp->postEvent() to send that object to the main thread. Then when the Qt event loop picks up and handles that QEvent in the main thread, that is the point at which your code can safely do things to the QLabels.
Alternatively (and perhaps more simply), your thread's code could emit a cross-thread signal (as described here) and let Qt handle the event-posting internally. That might be better for your purpose.
Neither of your approaches is thread-safe. It's possible that your first thread will execute the if statement, then the other thread will delete your label, and then you will be inside of your if statement and crash.
Qt provides a number of thread synchronization constructs, you'll probably want to start with QMutex and learn more about thread-safety before you continue working on this program.
Using a mutex would make your function would look something like this:
mutex.lock();
label1->show();
label2->show();
label3->show();
mutex.unlock()
As long as your other thread is using locking that same mutex object then it will prevented from deleting your labels while you're showing them.