Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Using QtConcurrent::map() with pointer to non-static member function



  • I have a linking problem when trying to use map, probably something is wrong with how I am wrapping objects/functions.

    I think some sample code is the best way to explain this case.

    @
    // class that contains data and parameters
    class workItem;

    // wrapper for pointer to member
    struct addWrapper {
    MainProgram *instance;
    addWrapper(MainProgram *prog) : instance(prog) {}
    void operator()(workItem &item) {
    instance->processItem(item);
    }
    };

    // non-static member function that I desire to process concurrently
    MainProgram::processItem(workItem &item);

    // function that uses concurrency to process many workItems
    MainProgram::someFunction()
    {
    // Make a list of work to process
    QList<workItem> schedule;
    ...

    addWrapper wrapper(this);
    QFuture<void> result = QtConcurrent::map(schedule, wrapper);
    

    }
    @

    When I compile, this is the output:
    @
    Undefined symbols for architecture x86_64:
    "QtConcurrent::BlockSizeManager::timeAfterUser()", referenced from:
    QtConcurrent::IterateKernel<QList<workItem>::iterator, void>::forThreadFunction() in mainprogram.o
    "QtConcurrent::BlockSizeManager::timeBeforeUser()", referenced from:
    QtConcurrent::IterateKernel<QList<workItem>::iterator, void>::forThreadFunction() in mainprogram.o
    "QtConcurrent::BlockSizeManager::blockSize()", referenced from:
    QtConcurrent::IterateKernel<QList<workItem>::iterator, void>::forThreadFunction() in mainprogram.o
    "QtConcurrent::BlockSizeManager::BlockSizeManager(int)", referenced from:
    QtConcurrent::IterateKernel<QList<workItem>::iterator, void>::forThreadFunction() in mainprogram.o
    "QtConcurrent::ThreadEngineBase::isCanceled()", referenced from:
    QtConcurrent::IterateKernel<QList<workItem>::iterator, void>::forThreadFunction() in mainprogram.o
    "QtConcurrent::ThreadEngineBase::startThread()", referenced from:
    QtConcurrent::IterateKernel<QList<workItem>::iterator, void>::whileThreadFunction() in mainprogram.o
    QtConcurrent::IterateKernel<QList<workItem>::iterator, void>::forThreadFunction() in mainprogram.o
    "QtConcurrent::ThreadEngineBase::waitForResume()", referenced from:
    QtConcurrent::IterateKernel<QList<workItem>::iterator, void>::whileThreadFunction() in mainprogram.o
    QtConcurrent::IterateKernel<QList<workItem>::iterator, void>::forThreadFunction() in mainprogram.o
    "QtConcurrent::ThreadEngineBase::setProgressRange(int, int)", referenced from:
    QtConcurrent::IterateKernel<QList<workItem>::iterator, void>::start() in mainprogram.o
    virtual thunk to QtConcurrent::IterateKernel<QList<workItem>::iterator, void>::start()in mainprogram.o
    "QtConcurrent::ThreadEngineBase::setProgressValue(int)", referenced from:
    QtConcurrent::IterateKernel<QList<workItem>::iterator, void>::forThreadFunction() in mainprogram.o
    "QtConcurrent::ThreadEngineBase::acquireBarrierSemaphore()", referenced from:
    QtConcurrent::ThreadEngine<void>::startAsynchronously() in mainprogram.o
    "QtConcurrent::ThreadEngineBase::isProgressReportingEnabled()", referenced from:
    QtConcurrent::IterateKernel<QList<workItem>::iterator, void>::start() in mainprogram.o
    virtual thunk to QtConcurrent::IterateKernel<QList<workItem>::iterator, void>::start()in mainprogram.o
    "QtConcurrent::ThreadEngineBase::run()", referenced from:
    vtable for QtConcurrent::ThreadEngine<void>in mainprogram.o
    vtable for QtConcurrent::IterateKernel<QList<workItem>::iterator, void>in mainprogram.o
    construction vtable for QtConcurrent::ThreadEngine<void>-in-QtConcurrent::IterateKernel<QList<workItem>::iterator, void>in mainprogram.o
    vtable for QtConcurrent::MapKernel<QList<workItem>::iterator, addWrapper> in mainprogram.o
    construction vtable for QtConcurrent::IterateKernel<QList<workItem>::iterator, void>-in-QtConcurrent::MapKernel<QList<workItem>::iterator, addWrapper>in mainprogram.o
    construction vtable for QtConcurrent::ThreadEngine<void>-in-QtConcurrent::MapKernel<QList<workItem>::iterator, addWrapper>in mainprogram.o
    "QtConcurrent::ThreadEngineBase::ThreadEngineBase()", referenced from:
    QFuture<void> QtConcurrent::map<QList<workItem>, addWrapper>(QList<workItem>&, addWrapper)in mainprogram.o
    "QtConcurrent::ThreadEngineBase::~ThreadEngineBase()", referenced from:
    virtual thunk to QtConcurrent::ThreadEngine<void>::~ThreadEngine()in mainprogram.o
    QtConcurrent::ThreadEngine<void>::~ThreadEngine()in mainprogram.o
    QtConcurrent::ThreadEngine<void>::~ThreadEngine()in mainprogram.o
    virtual thunk to QtConcurrent::ThreadEngine<void>::~ThreadEngine()in mainprogram.o
    virtual thunk to QtConcurrent::IterateKernel<QList<workItem>::iterator, void>::~IterateKernel()in mainprogram.o
    QtConcurrent::IterateKernel<QList<workItem>::iterator, void>::~IterateKernel()in mainprogram.o
    QtConcurrent::IterateKernel<QList<workItem>::iterator, void>::~IterateKernel()in mainprogram.o
    ...
    "typeinfo for QtConcurrent::ThreadEngineBase", referenced from:
    typeinfo for QtConcurrent::ThreadEngine<void>in mainprogram.o
    ld: symbol(s) not found for architecture x86_64
    collect2: ld returned 1 exit status
    @

    This is Qt 5.0.2 on MacOS X 10.8.3.

    Any help will be appreciated.

    Thanks



  • Everything seems to be OK with your wrapper. Have you added Qt5Concurrent library into linker options?

    However, there is a different problem, not connected with linker errors: you pass local 'schedule' to asynchronous 'map' as reference, but I don't see you wait for the computation finish. This way 'schedule' could go out of the scope during computation and you would get crash.



  • I'm not seeing QtConcurrent framework when linking.

    I thought QtConcurrent was part of QtCore.
    How do I add it to my .pro file ?



  • OK, so I did an experiment and you need QT += concurrent

    Thanks for spotting the error with schedule. I was hoping that map() was going to copy each object in the list... wishful thinking.


Log in to reply