Как правильно передать переменную-член в лямбда-функцию, которая будет выполняться в другом потоке в c ++? - PullRequest
0 голосов
/ 10 июля 2020

В моем приложении у меня есть поток событий и поток рендеринга. Я написал собственный класс потока, который может выполнять задачи (указатели на функции) с фиксированным интервалом, поэтому при необходимости я могу передавать работу между разными потоками.

Вот настройка: в потоке событий я анализирую файл это создаст модели, но прежде чем я смогу создать модели, я должен удалить старые, поэтому, естественно, я просто добавляю задачу очистки моделей следующим образом:

    WindowThread::getInstance()->addTask([this]() {
        this->viewport->clearModels();
    });

Эта функция в конечном итоге будет выполняться оконный поток, который, кажется, работает нормально, однако при отладке с помощью valgrind он сообщает следующую ошибку: valgrind invalid read of size 8 в строке, где вызывается clearModels (). После небольшого поиска в Google проблема, похоже, заключается в том, что указатель области просмотра (или это, я точно не знаю) находится за пределами адресной области памяти оконного потока, что имеет смысл, поскольку лямбда-функция была создана в событии thread.

Есть ли способ исправить эту «ошибку», перемещая указатель / лямбду в область памяти других потоков?

FThread :: addTask (const std :: function & task) добавляет заданную задачу в очередь std :: queue (которая заранее заблокирована мьютексом) из потока, в котором она вызывается. В конце концов очередь будет обработана потоком, в который была добавлена ​​задача.

void FThread::addTask(const std::function<void()> &task)
{
    if (this->m_running && this->m_taskQueueMode != QUEUE_DISABLED)
    {
        this->m_taskQueueMutex.lock();
        this->m_backTaskQueue->push(task);
        this->m_taskQueueMutex.unlock();
    }
}

void FThread::processTaskQueue()
{
    this->m_taskQueueMutex.lock();

    std::queue<std::function<void()>> *tmp = this->m_frontTaskQueue;
    this->m_frontTaskQueue = this->m_backTaskQueue;
    this->m_backTaskQueue = tmp;
    this->m_taskQueueMutex.unlock();

    while (!this->m_frontTaskQueue->empty())
    {
        this->m_frontTaskQueue->front()();
        this->m_frontTaskQueue->pop();
    }
}

Очередь задач настроена с двойной буферизацией, поэтому обработка текущих задач не блокирует добавление новых.

EDIT: Метод clearModels () просто удаляет каждый указатель в векторе, а затем очищает вектор.

void Viewport::clearModels()
{
    if (!this->models.empty())
    {
        for (auto *model : this->models)
            delete model;
        this->models.clear();
    }
    this->hiddenModels.clear();
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...