0

In my application I have an event thread and a render thread. I wrote a custom thread class that is able to execute tasks (function pointers) in a fixed interval so I can pass work between different threads if needed.

Here is the setup: In the event thread I parse a file that will create models, but before I can create models I have to delete the old ones, so naturally I just add the task of clearing the models like this:

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

This function will eventually be executed by the window thread, which seems to work fine, however when debugging with valgrind it reports the following error: valgrind invalid read of size 8 in the line where clearModels() is called. After a bit of googling the issue seems to be that the viewport pointer (or this, I don't know for sure) is outside of the memory address area of the window thread, which makes sense since the lambda function was created in the event thread.

Is there a way to fix this "error" by somehow moving the pointer/lambda into the other threads memory area?

FThread::addTask(const std::function<void()> &task) adds the given task to a std::queue (which is locked by a mutex beforehand) from the thread it is called in. Eventually the queue will be processed by the thread the task was added to.

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();
    }
}

The task queue is setup in a double buffered way so processing the current tasks doesn't block adding new ones.

EDIT: The clearModels() method is just deleting every pointer in a vector and then clearing the vector.

void Viewport::clearModels()
{
    if (!this->models.empty())
    {
        for (auto *model : this->models)
            delete model;
        this->models.clear();
    }
    this->hiddenModels.clear();
}
Masy
  • 151
  • 11
  • The error may well be in `clearModels()`, which you haven't shown here. Have you tried passing the function object by value? You might find this interesting:: https://stackoverflow.com/questions/17626667/why-function-objects-should-be-pass-by-value – jignatius Jul 09 '20 at 22:20
  • 1
    _After a bit of googling the issue seems to be that the viewport pointer (or this, I don't know for sure) is outside of the memory address area of the window thread, which makes sense since the lambda function was created in the event thread._ All threads in a process share the same addressing space, so it's not that. – Paul Sanders Jul 09 '20 at 22:40
  • @jignatius I added the method to the post. It is just deleting all models in a vector and then clearing the vector. Interestingly enough the check if the vector is empty is sometimes causing segfaults on windows, not on linux though. I'm unsure if I'm corrupting memory somewhere else or if it's a threading issue. – Masy Jul 10 '20 at 20:14
  • @Masy Is it possible that more than 1 thread could call `clearModels()` at any one time? If so, you will need thread synchronisation within the function. Use a mutex like you have in the other methods, or better still `std::lock_guard`. – jignatius Jul 10 '20 at 22:04
  • @Masy Also, do you have another function that adds to the vector `models`? If `clearModels()` is called at the same time another function tries to add to the vector that can cause a seg fault too. – jignatius Jul 10 '20 at 22:10

0 Answers0