01-08-2013 03:47 AM
I did some research before the holidays, and it seems that running something on a thread (or, generally speaking, without blocking the main thread) is a bit more difficult than i am used to (in BB java).
What i am looking for is something like this java code, with a simple runnable defined inline.
new Thread(runnable).start()
My current Qt code is based on this post:
http://mayaposch.wordpress.com/2011/11/01/how-to-r
QThread* thread = new QThread; DatabaseWorker* worker = new DatabaseWorker(); worker->moveToThread(thread); connect(worker, SIGNAL(result()), this, SLOT(onDatabaseResult())); connect(thread, SIGNAL(started()), worker, SLOT(process())); connect(worker, SIGNAL(finished()), thread, SLOT(quit())); connect(worker, SIGNAL(finished()), worker, SLOT(deleteLater())); connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); thread->start();
Basically my issue is that i have a fixed worker class, i would like to have something more flexible for operations that take some time, for example sqlite inserts. it's only 500ms, but it still makes the UI a bit slow.
01-08-2013 09:27 AM
01-08-2013 02:10 PM
You can use just simple threading in C. There is nothing that bounds you to QtThread (I think).
01-08-2013 05:00 PM - edited 01-08-2013 05:04 PM
This is generally what I do: Use pthread to start another thread, then move back to your object's method.
#include <pthread.h>
///////
// .h
void* decoding_thread(void* arg);
class YourClass {
friend void* decoding_thread(void* arg);
private:
void decoding_thread(void);
}
////////
// .cpp
void YourClass::something() { pthread_t pthread; pthread_create(&pthread, 0, &::decoding_thread, this /*YourClass reference*/ ); } void* decoding_thread(void* arg) { YourClass* yourClass = (YourClass*) arg; yourClass->decoding_thread();
return 0; } void YourClass::decoding_thread() {
// do something
}
01-08-2013 08:15 PM - edited 01-08-2013 08:17 PM
a QThread and signals and slots like you have is fine, but if you're worried about ballooning the number of interfaces, maybe consider a single signal for command and a single signal for response if it's a complex API?
eg.
QThread* thread = new QThread; DatabaseWorker* worker = new DatabaseWorker(); worker->moveToThread(thread); connect(worker, SIGNAL(request(args)), this, SLOT(onRequest(args))); connect(thread, SIGNAL(response(args)), worker, SLOT(onResponse(args))); thread->start();
then you could just pass commands to your thread using whatever args you need... be it enums, varargs, strings, etc.
even more interesting would be the ability to pass classes back and forth... consider:
class CommandResponse {
public:
CommandResponse(CmdType type) : mType(type), mError(EOK) {};
CmdType getType() { return mType; } // used to demux derived classes
int getError() { return mError; }
....
};
class FetchJpeg : public CommandResponse {
public:
FetchJpeg(char *url, int timeout) : CommandResponse(CMD_FETCHJPEG), mTimeout(timeout), mBuf(NULL) { mUrl=strdup(url); }
~FetchJpeg() { free(mUrl); free(mData); ... }
void getBuffer(char **buf, int *size) { *buf = mBuf; *size = mSize; }
....
};
then you could just allocate a FetchJpeg(...) command, emit it via ::request() and then catch the replies on your :
nResponse() handler and pull the details using response->getBuffer(&buf, &size); and render.
Though this is effectively just pushing command multiplexing up one layer into your code, but otherwise is equivalent to defining a ton of signals and slots.
Maybe I'm misunderstanding your concern though...
Cheers,
Sean
01-09-2013 03:02 AM
I think what i am looking for is something like the java Runnable interface, where i can overwrite the run method with whatever i want to do.
This would be the java code, which can be used (and re-used) for all kind of fire and forget code.
new Thread() {
public void run() {
//process blocking code
}
}.start();
I guess that is just a java design and not reproducable in c++/Qt?
01-09-2013 10:16 AM - edited 01-09-2013 10:26 AM
Isn't that just QThread::run() ?
void MyThread::run() {
// calculate Pi to 1-billion digits....
}
Or alternately, using plain old pthreads:
void *calculate_pi(void* arg) {
// calculate pi to 1-billion digits
}
pthread_create(&tid, NULL, calculate_pi, NULL);
Or similar to what mreed suggested, but using a static method in your class....
class MyApp {
static void* threadEntryPoint(void* arg);
void* myThread();
pthread_t mTid;
};
// static wrapper for use with pthreads
void* MyApp::threadEntryPoint(void* arg) {
MyApp* instance = (MyApp*)arg;
return instance->myThread();
}
void* MyApp::myThread() {
// whatever blocking code you want...
}
// start the thread
pthread_create(&mTid, NULL, threadEntryPoint, (void*)this);
Note that starting a pthread with the default pthread_attr_t (NULL) will produce a thread that needs to be joined later. If you really want a fire-and-forget <tm> function, then make sure to start the thread detached:
pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); pthread_create(&mTid, &attr, threadEntryPoint, (void*)this);
Cheers,
Sean
01-09-2013 12:01 PM
smcveigh wrote:
Isn't that just QThread::run() ?
maybe. Could you give me a quick sample that runs
qDebug() << "i am a thread"
on a qthread?
and isn't that the "evil" subclassing that you are not supposed to do?
keep in mind, i am quite new to the c++/Qt world ![]()
01-09-2013 12:21 PM - edited 01-09-2013 12:29 PM
I don't know why subclassing would be considered evil.. if they didn't want you to do it, they wouldn't have made the ::run() method virtual ![]()
Disclaimer: I haven't used QThreads, so not sure how to start them up, but this seems like the sort of thing you'd want to do...
class MyThread : public QThread {
public:
MyThread(QObject *parent = 0) : QThread(parent) {}
protected:
virtual void run();
};
void MyThread::run() {
qDebug() << "I am a thread";
// don't call exec() if you don't want to run the event loop
}
// run that thread...
MyThread thread;
thread.start(); // I assume this is how you start a QThread?
The Qt docs show something similar:
http://doc.qt.digia.com/qt/qthread.html
The starting point for the thread. After calling start(), the newly created thread calls this function. The default implementation simply calls exec().
You can reimplemented this function to do other useful work. Returning from this method will end the execution of the thread.
Cheers,
Sean
01-09-2013 12:24 PM