PDA

View Full Version : cancel slot not getting called with QtConcurrent::run()



prasad_N
27th June 2015, 22:29
I am trying to implement the multi threading programming.

Prob: I need to read huge data from Db (Which will be done through 3rd party API for which i don't have control), So my plan is so create ideal number of threads (max 5)
and each thread reads chunk of data at the end all the chunks will be merged. (I should be able to cancel the process in middle if I don't want).

I just tried below sample code(Before going to above implementation), when I click on cancel button It's slot is not get called, instead slot will be getting called after all the threads finished.


// I am just doing some busy work here As I don't know what is happening here, this function is not in my control
QVector<int> thirdPartyFunction()
{
QTime time;
int t1 = time.elapsed()/1000;

while( ((time.elapsed()/1000) - t1) < 3)
{

}
return QVector<int>();
}

QVector<int> myThread()
{
return thirdPartyFunction();
}


Dialog::Dialog(QWidget *parent) : QDialog(parent)
{
progress = new QProgressDialog("Threading in progress", "Cancel", 0, 100, this);
connect(progress, SIGNAL(canceled()), this, SLOT(cancelAllThreads()), Qt::QueuedConnection);

progress->setValue(0);

// starting 5 threads
for(int i=0; i< 5; i++)
{
synch.addFuture(QtConcurrent::run(myThread));
progress->setValue(progress->value() + 10);
}

synch.waitForFinished();
QVector<int> finalList;


if(synch.cancelOnWait())
{
qDebug() << "cancel all the threads......";
}
else
{
//if I never press cancel
QList<QFuture< QVector<int> > > futuresList = synch.futures();

for ( int i = 0; i < futuresList.size(); i++ )
{
QVector<int> list = futuresList.at(i);
finalList << list;

progress->setValue(progress->value() + 10);
qDebug() << "pro val = " << progress->value() + 10;
}
qDebug() << "All threads finished successfully - size" << finalList.size();
}
}

Dialog::~Dialog()
{
}

//this is not getting called as soon as I licked cancel
void Dialog::cancelAllThreads()
{
//here I want to cancel & clean up all the threads
qDebug() << "Canceled pressed....";
synch.setCancelOnWait(true);
}


Now difficulties I am facing are:

1. GUI is not responding even if I click cancel. So cancelAllThreads() is not getting called (GUI thread is freezing some how),
this function is getting called when all the threads are finished even I cancel in middle.
2. I am not able to update progress bar values properly (As I don't have control over thirdPartyFunction, so while creating thread i am showing 50% &
when all the threads finished another 50% but this will give bad experience to the user as showing 50% at start and wait for long long time and then suddenly 100%).
3. Qt doc said I can not cancel QtConcurrent::run(..), is there a way to stop/kill this thread in middle
(doc said can not cancel but looking for some smart idea if possible) ?


What am I doing wrong here??

anda_skoa
28th June 2015, 10:03
You are blocking the UI thread in waitForFinished().

Cheers,
-

prasad_N
28th June 2015, 10:29
But I need to synchronise all the result at the end so I am just waiting till all the threads finished their computations.. any other way to do it or wait without blocking main thread.

anda_skoa
28th June 2015, 12:50
QFutureWatcher can be used to be notified about a QFuture's completion.

Cheers,
_

prasad_N
28th June 2015, 15:56
Thanks. What about canceling these threads, is there away to stop this threads in middle once started ??

anda_skoa
28th June 2015, 16:24
Not without cooperation of the threads.
The threads need to check for a exit/cancel condition and then cease doing their work.

Maybe you can split the tasks in a series of subtasks and then peform such a check between each step.

Cheers,
_

prasad_N
28th June 2015, 16:37
I can not do it as series of action. The reason i switched to threading is I need to decrease the reading time as much as posible.

anda_skoa
28th June 2015, 19:15
So you can split it into 5 units of work an no further?
What are those 5 tasks?

Cheers,
_

prasad_N
28th June 2015, 19:39
If suppose I need to read 5 lak rows of data from DB, I am starting 5 threads so that each thread read 1 lak rows, at the end I will merge the result.
The thing is that reading records is from third party function so I do not have control over it(I don't know what is happening inside, how much time will take, I cant not put any bool variable inside it to stop at particular condition ...).

anda_skoa
28th June 2015, 19:52
So the third party API only allows you to read 1 lak rows, no smaller amount?

I.e. you can't read 50 times 0.1 lak rows?

Cheers,
_

prasad_N
28th June 2015, 20:14
So the third party API only allows you to read 1 lak rows, no smaller amount?

I can read any number, just I need to pass boundaries (start row & end row Indexes).


I.e. you can't read 50 times 0.1 lak rows?

I can, But what is the use of this approach reading 50 times 0.1 lak rows? (Sorry I may not get your logic)

Note: We did some experiment and find out that more that 8 threads are slowing down the performance on my machines.
So we are running max 8 threads to to read entire data.

anda_skoa
29th June 2015, 10:43
I can read any number, just I need to pass boundaries (start row & end row Indexes).

Then you can split the work into smaller steps, which you said you could not (comment #7)



I can, But what is the use of this approach reading 50 times 0.1 lak rows? (Sorry I may not get your logic)

Smaller units of work take less time, waiting for such a smaller amount of time on cancel makes the program react to cancel faster.



Note: We did some experiment and find out that more that 8 threads are slowing down the performance on my machines.
So we are running max 8 threads to to read entire data.
I already thought that 5 threads are pretty optimistic, but I am not suggesting increasing the number of threads at all.

Cheers,
_

prasad_N
29th June 2015, 13:16
Then you can split the work into smaller steps, which you said you could not (comment #7)_

yes, it could have been I don't want instead I cann't :-)



Smaller units of work take less time, waiting for such a smaller amount of time on cancel makes the program react to cancel faster._

I will try this and get back with the result, I need to check how much time it will take to read entire DB (My main aim is to minimize reading time).


I already thought that 5 threads are pretty optimistic, but I am not suggesting increasing the number of threads at all._

I am working on SLES11 server(high end machine), more that 5 threads might works in my case.