PDA

View Full Version : [QThread][QQueue] - logic problem !



Abdelhadi
18th April 2014, 14:26
Hi everyone,

Directly to the matter !,

- i have an application that have a parent class and two child classes
- i have a queue of QUrl's (retrived from a table)
- according to the url scheme i call one of the two classes method (with the same name, overriden !)



if(url.scheme() == ...){
Parent* p = new ChildA;
p.DoSomething(url);
}
else if (url.scheme() == ...){
Parent* p = new ChildB;
p.DoSomething(url);
}



- at the end of the DoSomething(url) i delete the QUrl from the table,

What i want to do : having a max of 10 thread (for example), to do 10 DoSomething(url) at the same time, and at the end of one DoSomething(url) i call another do something on another thread with a newer url while the queue is not empty !

so how i can do that ?
another question : i use a QSqlDatabase on DoSomething(), can i use the same connection as a global variable or i have to create a new connection on each thread ?

Thanks in advance , have a good day :)

PS : i use Qt4, qtcreator as an IDE on linux

anda_skoa
18th April 2014, 16:31
You could make ChildA and ChildB implement the QRunnable Interface and then use a QThreadPool with 10 threads.

Or, if you prefer manual thread handling, share a QSemaphore instance between your threads, initialized to 10, and have each thread acquire() it before it runs the operation and release() it when it is done.

No idea about the database thread safety, that might depend on the driver, etc.

Cheers,
_

Lesiok
18th April 2014, 16:36
From Qt doc (http://qt-project.org/doc/qt-4.8/threads-modules.html) : A connection can only be used from within the thread that created it. Moving connections between threads or creating queries from a different thread is not supported.

Abdelhadi
18th April 2014, 21:28
You could make ChildA and ChildB implement the QRunnable Interface and then use a QThreadPool with 10 threads.

Or, if you prefer manual thread handling, share a QSemaphore instance between your threads, initialized to 10, and have each thread acquire() it before it runs the operation and release() it when it is done.

No idea about the database thread safety, that might depend on the driver, etc.

Cheers,
_

Thank's for your reply, i have questions about each method if you don't mind:

1 - about QThreadPool, do i have to create 10 different instances for ChildA/ChildB ?!, can you give me a good practice for this method :)
2 - about QSemaphore, how i manage my QQueue with it ?

let me explain better what i want to do : i have a list of Qurl's and depending on url scheme i instantiate ChildA or ChildB to run an overloaded method that takes the QUrl as parameter (it's always the same method), example :



QQueue<QUrl> queue;
foreach (QUrl url, urlsList){
queue.enqueue(url);
}
while (!queue.isEmpty()){
QUrl url = queue.dequeue();
if(url.scheme() == ...){
Parent * p = new ChildA;
p.DoSomething(url);
}
else if (url.scheme() == ...){
Parent * p = new ChildB;
p.DoSomething(url);
}
}


that means that i have to wait DoSomething(url) finish to treat the next url, what i want is doing this 10 times at the same time (treating 10 url's at the same time whatever the scheme) !

sorry for my stupid questions, i'm a new bee :)



From Qt doc (http://qt-project.org/doc/qt-4.8/threads-modules.html) : A connection can only be used from within the thread that created it. Moving connections between threads or creating queries from a different thread is not supported.

Thank's for your reply, do you mean by that the QSqlDatabse ?


Thank's eveyone
Cheers:)

anda_skoa
20th April 2014, 14:01
1 - about [B]QThreadPool, do i have to create 10 different instances for ChildA/ChildB ?!, can you give me a good practice for this method :)

More or less.

The idea of a thread pool is that you have tasks. You create an instance of classes with a certain interface, each instance handling a single task. Then you enqueue these task objects on a thread pool.
The pool then has each of its thread process one task and pick a new one when they are done (or make them wait until new tasks are available).

You code snippet looked a lot like that approach.



class ChildATask : public ChildA, public QRunnable
{
public:
ChildATask(const QUrl &url) : ChildA(), m_url(url) {}

void run() {
DoSomething(m_url);
}

private:
QUrl m_url;
};

Or comibine that into ChildA itself.



while (!queue.isEmpty()){
QUrl url = queue.dequeue();
if(url.scheme() == ...){
Parent * p = new ChildATask;
threadPool.start(p);
}
else if (url.scheme() == ...){
Parent * p = new ChildB;
threadPool.start(p);
}
}




2 - about QSemaphore, how i manage my QQueue with it ?

The semaphore would be used to limit the amount of parallelism, not the access to the queue.

Lets assume that each of your Child classes uses a separate thread and each thread would call release() on the semaphore before it exits.

So your work distribution loop would do something like this:


while (!queue.isEmpty()){

semaphore.acquire();

QUrl url = queue.dequeue();
if(url.scheme() == ...){
Parent * p = new ChildA;
p.DoSomething(url);
}
else if (url.scheme() == ...){
Parent * p = new ChildB;
p.DoSomething(url);
}
}

If the semaphore has been initialized with 10, then the loop can acquire() it then times before any thread needs to be done. After that it will wait in acquire() until at least one of the 10 already running threads is done.

Cheers,
_