Search code examples
c++multithreadingmutexsemaphoredata-race

Segfault occuring in attempt to synchronize queue


I am learning about multithreading and I wanted to simulate producer-consumer problem ( using semaphore if I can call it that ).

I have a class that holds a queue, producer push ints into queue and consumer retrieves it and prints it. I simulated is as following

class TestClass{
public:
    void producer( int i ){
        unique_lock<mutex> l(m);
        q.push(i);
        if( q.size() )
            cnd.notify_all();
    }

    void consumer(){
        unique_lock<mutex> l(m);
        while( q.empty() ){
            cnd.wait(l);
        }
        int tmp = q.front();
        q.pop();
        cout << "Producer got " << tmp << endl;
    }
    void ConsumerInit( int threads ){
        for( int i = 0; i < threads; i++ ){
            thrs[i] = thread(&TestClass::consumer, this );
        }
        for( auto &a : thrs )
            a.join();
    }


private:
    queue<int> q;
    vector<thread> thrs;
    mutex m;
    condition_variable cnd;
};

And I used a little console application to call data:

int main(){
    int x;   
    TestClass t;
    int counter = 0;
    while( cin >> x ){
        if( x == 0 )
            break;
        if( x == 1)
            t.producer(counter++);
        if( x == 2 )
            t.ConsumerInit(5);
    }   
}

So when user input 1, a data is pushed into the queue , if user press 2 threads are spawned.

In any order of invoking it, for example, pressing 1 1 and then 2, or 2 1 1 it throws segfault. I am not sure why my understanding of my code is as following: let's assume order 2 1 1

I initialize 5 threads, they see that queue is empty, so they go to sleep. When I push a number to the queue, it notifies all threads sleeping. The first one to wake up lock mutex again and proceed to retrieve number from queue and afterwards releasing the mutex, when mutex is released another thread do the same and unlocks the mutex, the third thread after mutex is unlocked is still in loop and see that queue is yet again empty and goes to sleep again, same with all remaining threads.

Is this logic correct? If so, why does this keep throwing segfault, if not, I appreciate all explanations.

Thanks for the help!

//edit By answers suggets , i replaced [] with vector.push_back , but consumer does nothing with data now , does not take it or print it.


Solution

  • You aren't expanding the thrs vector when you do

    thrs[i] = thread(&CTest::consumer, this );
    

    You should do

    thrs.emplace_back(&CTest::consumer, this);
    

    That's where the crash would be.