CybeX
CybeX

Reputation: 2406

Using QtConcurrent::map() function on QList yields segmentation fault

I am familiarizing myself with QtConcurrent library. I have a UI (MainWindow) where I run my functions to simulate a real world example of multithreading.

The QtConcurrent::map() function I am using requires some:

  1. Iterator or a Sequence, in my case I am using a QList.
  2. Further, it requires a MapFunctor (which supports lambdas*) but for this purpose, I am choosing to stick to a static method for testing.

What I have tried

I attempted using both map() functions (the first is left uncommented)

I tried searching for a Sequence and a MapFunctor, but I could only find it in templates which did not help alot, thus I had to try and use my intuition to make sense of it.

The Code:

Somewhere inside my MainWindow.cpp

// counter variable stored in MainWindow
int i = 0;

// MapFunctor
void mapSumToQString(QPair<int, int> pair)
{
    i++;
    qDebug() << "Execute " << i << " = " << QString::number(pair.first, pair.second);;
}

and the code to start it all

// UI class decl
MainWindow::MainWindow(QWidget* parent)
     : QMainWindow(parent)
     , ui(new Ui::MainWindow)
{
     ui->setupUi(this);

     // Create list of integers to perform map function on (here I don't write back to the original sequence i.e. list)
     QList<QPair<int, int>> intPairList = QList<QPair<int, int>>();
     for (int i = 0; i < 1000; i++) {
         int i1 = qrand();
         int i2 = qrand();
         intPairList.append(QPair<int, int>(i1, i2));
     }

     QFuture<void> future;
     future = QtConcurrent::map(intPairList, mapSumToQString);
     // future = QtConcurrent::map(intPairList.begin(), intPairList.end(), mapSumToQString);
}

Problem:

Running this snippet of code results in a SEGV here

namespace QtConcurrent {
// map kernel, works with both parallel-for and parallel-while
template <typename Iterator, typename MapFunctor>
class MapKernel : public IterateKernel<Iterator, void>
{
    MapFunctor map;
public:
    typedef void ReturnType;
    MapKernel(Iterator begin, Iterator end, MapFunctor _map)
        : IterateKernel<Iterator, void>(begin, end), map(_map)
    { }
    bool runIteration(Iterator it, int, void *) override
    {
        map(*it);                       <--------SEGV line
        return false;
    }

    //...
}

Stacktrace (copied from debugger)

1  QtConcurrent::MapKernel<QList<QPair<int, int>>::iterator, QtConcurrent::FunctionWrapper1<void, QPair<int, int>>>::runIteration  qtconcurrentmapkernel.h      68  0x404ee8   
2  QtConcurrent::MapKernel<QList<QPair<int, int>>::iterator, QtConcurrent::FunctionWrapper1<void, QPair<int, int>>>::runIterations qtconcurrentmapkernel.h      77  0x404f82   
3  QtConcurrent::IterateKernel<QList<QPair<int, int>>::iterator, void>::forThreadFunction                                          qtconcurrentiteratekernel.h  255 0x40466e   
4  QtConcurrent::IterateKernel<QList<QPair<int, int>>::iterator, void>::threadFunction                                             qtconcurrentiteratekernel.h  217 0x404486   
5  QtConcurrent::ThreadEngineBase::run                                                                                             qtconcurrentthreadengine.cpp 302 0x6d881973 
6  QThreadPoolThread::run                                                                                                          qthreadpool.cpp              99  0x111b36a  
7  QThreadPrivate::start(void *) *4                                                                                                qthread_win.cpp              403 0x11163eb  
8  KERNEL32!BaseThreadInitThunk                                                                                                                                     0x74d56359 
9  ntdll!RtlGetAppContainerNamedObjectPath                                                                                                                          0x77467c24 
10 ntdll!RtlGetAppContainerNamedObjectPath                                                                                                                          0x77467bf4 
11 ??

For the record, there is another question related to this, but most certainly does not provide a usable solution.

Why do I get this SEGV, what is causing this access violation?

Upvotes: 0

Views: 369

Answers (1)

Saeed Sayyadipour
Saeed Sayyadipour

Reputation: 550

Honestly, some parts of your question are not clear for me. However, please take into account the followings (although you may have considered some or all of them):

  1. the functor is highly recommended to be a static function. From your code, it seems that you may have not declared the static function properly. Please put the following in your MainWindow.h:
static void mapSumToQString(QPair<int, int> pair);

and modify the implementation as follows:

// MapFunctor
void MainWindow::mapSumToQString(QPair<int, int> pair)
{
    j++;
    qDebug() << "Execute " << j << " = " << QString::number(pair.first, pair.second);;
}
  1. mapSumToQString is static, hence you cannot use non-static members of the MainWindow inside it. Hence, the i must be static as well.
static int j; //in MainWindow.h ---> I changed i to j to make it differ from your For loop variable
int MainWindow::j = 0;//in MainWindow.cpp ----> static variables have to be initialized
  1. Modify MainWindow.cpp as follows:
    // counter variable stored in MainWindow
    j = 0;

    QFuture<void> future;
    future = QtConcurrent::map(intPairList, mapSumToQString);
    future.waitForFinished();
  1. One thing that I cannot understand is that you are converting an integer to a string with a random base?!
qDebug() << "Execute " << j << " = " << QString::number(pair.first, pair.second);
//Herein, pair.second is random, and hence QString::number's second input (base) is always a random number. Do you really want it?

Upvotes: 0

Related Questions