cbaakman
cbaakman

Reputation: 61

Why does my multithreaded job queue crash?

I'm trying to run a multi-threaded job queue in c++. As an example I have tested the following program:

#include <thread>
#include <mutex>
#include <list>
#include <vector>


class Job
{
    public:
        void Run(void)
        {
        }
};


class Queue
{
    private:
        std::recursive_mutex mtxJobs;
        std::list<Job *> mJobs;
    public:
        Job *Take(void)
        {
            std::scoped_lock(mtxJobs);
            if (mJobs.size() > 0)
            {
                Job *pJob(mJobs.front());
                mJobs.pop_front();
                return pJob;
            }
            else
                return NULL;
        }

        void Add(Job *pJob)
        {
            std::scoped_lock(mtxJobs);
            mJobs.push_back(pJob);
        }

        size_t Size(void)
        {
            std::scoped_lock(mtxJobs);
            return mJobs.size();
        }
};


void Work(Queue &q)
{
    Job *pJob;
    while ((pJob = q.Take()) != NULL)
    {
        pJob->Run();

        delete pJob;
    }
}

int main()
{
    size_t i;
    Queue q;

    for (i = 0; i < 1000; i++)
        q.Add(new Job);

    std::vector<std::thread> threads(4);
    for (i = 0; i < 4; i++)
        threads[i] = std::thread(Work, std::ref(q));

    for (i = 0; i < 4; i++)
        threads[i].join();

    return 0;
}

When I run it like this:

g++ -std=c++17 -lpthread test.cpp -o test && ./test

it crashes with a SEGFAULT. Does anyone have any idea why?

GDB indicates that the crash always occurs when the list 'mJobs' is accessed. However, the locks should prevent concurrent modification right?

Can anyone help me?

Upvotes: 2

Views: 161

Answers (1)

rafix07
rafix07

Reputation: 20959

You are accessing your queue without synchronization:

std::scoped_lock(mtxJobs);

this is local variable with name mtxJobs which is created taking no arguments and hides your mutex mtxJobs member. When scoped_lock is created without arguments it does nothing according to reference.

You need to write:

std::scoped_lock lock(mtxJobs);

now, your mutex is locked in ctor of scoped_lock object.

Upvotes: 3

Related Questions