0

I would like to cancel a QtConcurent::map computation at an event.

This is my test code (the computation is represented by an infinite loop) :

class Test : public QObject
{
    Q_OBJECT

public:
    Test(QObject *parent=0) : QObject(parent){}

    void test()
    {
        qDebug() << tr("thread:") <<  QThread::currentThread();

        //computation
        while(true);
    }
};

I have a list of Test, and I do :

//QFuture<void> m_concurentResult;
m_concurentResult = QtConcurrent::map(m_collection, &Test::test);
//That's Ok, I have the two outputs :
//  QThread(0x4e21f8, name = "Thread (pooled)")
//  QThread(0x4e21b8, name = "Thread (pooled)")

The goal is to cancel all the computation when the user click a button.

void Widget::on_pushButton_clicked()
{
    m_concurentResult.cancel();
    m_concurentResult.waitForFinished();
}

But when I click the button, the UI is freezed, and nothing is done. Thank's for help !

saad
  • 764
  • 4
  • 18

2 Answers2

1

Apart from the fact that I would check if cancel does actually do something (that is, I wouldn't be surprised if it's not implemented), you're missing the point of it: it doesn't cancel the tasks currently running, but it prevents further tasks to be scheduled for that computation.

So if for instance you're running a map on 10 items (1 .. 10), and items 1 and 2 are being processed, and you invoke cancel, the ongoing computation on 1 and 2 will complete; possibly no further items will be processed (but you get no guarantees on that).

The problem, in general, is that you can't easily cancel a thread. For instance, Qt doesn't suppor it for QThreads.

peppe
  • 21,934
  • 4
  • 55
  • 70
0

As Peppe said, QTConcurrent only cancels further processing (if you do map or filter over a sequence). A single item cannot be interrupted.

This is because Threads in general can't be canceled or interrupted.

In C++, you need to manage this yourself. (There was talk about extending C++ with the possibility to interrupt/cancel threads by pushing an exception to a thread, where it would throw, but the details were too hairy to get into the standard.)

For some languages that run a VM (Java, Python) it's doable when that thread is executing Java/Python code, but not when locked on a kernel/native) operation.

So, while(true) should be while(!m_interrupted).

Macke
  • 24,812
  • 7
  • 82
  • 118
  • Ok, I have "volatil bool m_interrupted" on the class Test. I add a public slot void interrupt(), that make m_interrupted to true. From the main thread, I connect a signal to slots of all objects Test in the collection. Should I have a Direct, Queued or Auto Connection? The slot is it executed in the main thread or in the pool thread ? Thank you ! – saad Jan 24 '14 at 13:25
  • @saad: Edit your question. to show new code. And read the documentation on slot connection. It depends on which thread the qobject belongs to, since it's the slot connection is sent from the eventloop running in the thread. – Macke Jan 24 '14 at 14:33