QtConcurrent::map() vs. QtConcurrent::run() for member function



  • I have a QWidget class called "createCPInput" with a public member function "void generateAxtCPseq()" and a slot "void on_generateCPInputButton_clicked()". the function generateAxtCPseq() can take a long time to run so I run it within "on_generateCPInputButton_clicked()" using QtConcurrent::run() so that it runs in a separate thread.

    I want to be able to get progress signals and be able to cancel the thread, these features aren't compatible for QtConcurrent::run() but are compatible for QtConcurrent::map(). I haven't been able to figure out a way to run generateAxtCPseq() using QtConcurrent::map().

    If anyone has some suggestions that would be great.

    Here is the relevant code I have at the moment which runs fine but doesn't allow me the functionality I require:
    createcpinput.h

    @
    public:
    void generateAxtCPSeq();

    private slots:
    void on_generateCPInputButton_clicked();
    @

    createcpinput.cpp
    @
    void createCPInput::on_generateCPInputButton_clicked(){
    typedef QFutureWatcher<void> voidWatcher;
    voidWatcher *axtWatcher = new voidWatcher(this);
    axtWatcher->setFuture(QtConcurrent::run(this,&createCPInput::generateAxtCPSeq));
    }

    void createCPInput::generateAxtCPSeq(){
    //Computationally expensive task
    }
    @



  • QtConcurrent::map() has the following interface:
    @map(Sequence &sequence, MapFunction function)@

    Hence you need a Sequence, containing the items to be processed, plus a MapFunction, which will be called once for each item to be processed.

    Also your MapFunction function must take a reference to an item as input and it must process that item. It can not be an arbitrary function!

    BTW: The reason why QtConcurrent::map() can be "cancelled" is because it will call your function once for each item. So it can simply stop calling your function before all items have been processed, when "cancellation" is requested. It still cannot "abort" a single call of your function!

    __

    See also:
    http://qt-project.org/doc/qt-4.8/qtconcurrent-map-main-cpp.html



  • Thanks MuldeR for the reply.

    So, It seems like I'm going down the wrong path for what I want to do.

    The reason generateAxtCPSeq() takes a long time is because it reads in large data files and writes out a large amount of data. Initially I had this running in the same thread when on_generateCPInputButton_clicked() was called. This was causing my GUI to be non-responsive. After some searching I found this: http://doc.qt.digia.com/qq/qq27-responsive-guis.html. But because I call the function generateAxtCPSeq() only once there isn't a way to cancel it or get progress signals from it.

    Is there a way to perform the reading and writing in another thread but be able to cancel and get progress reports from it? it doesn't seem obvious because the reading and writing needs to happen sequentially (reading in line by line).



  • Hi, perhaps instead try a "QThread class":https://qt-project.org/doc/qt-5/qthread.html . And you can use signal/slots for cancels and process reports.



  • You cannot abort generateAxtCPSeq(), unless that function offers a way to do so! Of course you could run the function is a separate thread, e.g. by using QThread. Then you could simply kill the thread in order to "abort" the function. But this is inherently unsafe! You would kill the function at an arbitary position, resulting in undefined behavior. You can get resource leaks and other evils. Don't do this, if it can be avoided!

    Better change your function like this:
    @bool generateAxtCPSeq(volatile bool *abortFlag)
    {
    while((!completed) && (!(*abortFlag)))
    {
    doNextStep();
    }
    return complete;
    }@

    Then you could pass a pointer to a global "abortFlag" variable, which you set to false initially and which you can set to true, from the "main" thread, in order to abort the function call. This of course assumes your function can be broken down into a number of "short" steps.

    __

    It could look like this:

    @class MyThread : public QThread
    {
    public:
    MyThread(void)
    {
    m_success = m_abortFlag = false;
    }

    void abortFunction(void)
    {
        m_abortFlag = true;
    }
    

    protected:
    virtual void run(void)
    {
    m_success = generateAxtCPSeq(&m_abortFlag);
    }

    volatile bool m_abortFlag;
    volatile bool m_success;
    

    };@
    @void MyDialog::startButtonPressed(void)
    {
    m_thread->start();
    }

    void MyDialog::abortButtonPresed(void)
    {
    m_thread->abortFunction();
    }@



  • Thanks MuldeR that's really helpful :D


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.