首页 > 解决方案 > 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?

标签: c++multithreadingqtqtconcurrentqfuture

解决方案


老实说,您的问题的某些部分对我来说并不清楚。但是,请考虑以下几点(尽管您可能已经考虑了部分或全部):

  1. 强烈建议仿函数是静态函数。从您的代码看来,您可能没有正确声明静态函数。请在 MainWindow.h 中添加以下内容:
static void mapSumToQString(QPair<int, int> pair);

并修改实现如下:

// MapFunctor
void MainWindow::mapSumToQString(QPair<int, int> pair)
{
    j++;
    qDebug() << "Execute " << j << " = " << QString::number(pair.first, pair.second);;
}
  1. mapSumToQString是静态的,因此您不能在MainWindow其中使用非静态成员。因此,i也必须是静态的。
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. 修改 MainWindow.cpp 如下:
    // counter variable stored in MainWindow
    j = 0;

    QFuture<void> future;
    future = QtConcurrent::map(intPairList, mapSumToQString);
    future.waitForFinished();
  1. 我无法理解的一件事是您正在将整数转换为具有随机基数的字符串?!
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?

推荐阅读