Suresh Atukuri
Suresh Atukuri

Reputation: 13

Getting Segfault while Creating a Queue using Vector of Threads in C++

I am getting Segmentation fault: 11 while Creating a Queue using Vector of Threads, could you please help me to fix.

#include <thread>
#include <queue>
#include <iostream>
using namespace std;

int tcount = 0;

template <typename T>
void thread_spawn_q(queue<T> &q)
{
    vector<thread> ths;
    for (int i = 1; i <= 20000; i++)
    {
        ths.push_back(thread(static_cast<void (queue<T>::*)(T &&)>(&queue<T>::push), &q, to_string(i)));
        ++tcount;
    }
    for (auto &th : ths)
    {
        th.join();
    }
}
int main()
{
    queue<string> q = queue<string>();
    thread_spawn_q(q);
    cout << "tcount:" << tcount << endl;
    return 0;
}

Edit#1

Making only 5 threads instead of 20000. I am still getting Segfault intermittently and also error: pointer being freed was not allocated.

cpptest$ ./sof_test2.exec

tcount:5

cpptest$ ./sof_test2.exec

tcount:5

sof_test2.exec(77351,0x11944be00) malloc: *** error for object 0x100000010: pointer being freed was not allocated

sof_test2.exec(77351,0x11944be00) malloc: *** set a breakpoint in malloc_error_break to debug

Abort trap: 6

cpptest$ ./sof_test2.exec

tcount:5

cpptest$ ./sof_test2.exec

tcount:5

sof_test2.exec(77358,0x10dbd9e00) malloc: *** error for object 0x2000000000000: pointer being freed was not allocated

sof_test2.exec(77358,0x10dbd9e00) malloc: *** set a breakpoint in malloc_error_break to debug

Abort trap: 6

cpptest$ ./sof_test2.exec

tcount:5

cpptest$ ./sof_test2.exec

Segmentation fault: 11

cpptest$ ./sof_test2.exec

tcount:5

sof_test2.exec(77368,0x10f1f7e00) malloc: *** error for object 0x100007fcb4c405dc: pointer being freed was not allocated

sof_test2.exec(77368,0x10f1f7e00) malloc: *** set a breakpoint in malloc_error_break to debug

Abort trap: 6

Upvotes: 1

Views: 113

Answers (1)

Ben
Ben

Reputation: 9703

As @273K says: "standard containers are not thread safe": you need to syncronize using a mutex, like this:

#include <iostream>
#include <mutex>
#include <queue>
#include <thread>

int tcount{0};

template <typename T>
void thread_spawn_q(std::queue<T> &q)
{
    std::vector<std::thread> ths;
    std::mutex mutex;
    for (int i = 1; i <= 5; i++)
    {
        // Your version: ths.push_back(thread(static_cast<void (queue<T>::*)(T &&)>(&queue<T>::push), &q, to_string(i)));
        /* Easier-to-read version of same:
        ths.push_back(std::thread(
            [&q](int i) {
                q.push(std::to_string(i));
            },
            i));*/
        // Correct version, using a mutex
        ths.push_back(std::thread(
            [&q, &mutex](int i) {
                // We still call std::to_string in parallel...
                auto s = std::to_string(i);
                std::unique_lock lock{mutex};
                // ... but only one thread at a time is looking at q while it's being modified:
                q.push(std::move(s));
            },
            i));
        ++tcount;
    }
    for (auto &th : ths)
    {
        th.join();
    }
}
int main()
{
    auto q = std::queue<std::string>();
    thread_spawn_q(q);
    std::cout << "tcount:" << tcount << std::endl;
    return 0;
}

https://godbolt.org/z/KzWKqsz9n

Upvotes: 1

Related Questions