Search code examples
c++boostboost-thread

boost failing to obtain lock


I am working on a real-time music application. Working with boost library as a newbie. I implemented a Producer/Consumer relationship with a protected SyncronizedQueue, actually I implemented the 18.11 and 18.12 sections of https://www.quantnet.com/cplusplus-multithreading-boost/. When parsing the midi input I get the following exception:

terminate called after throwing an instance of 'boost::exception_detail::clone_impl
<boost::exception_detail::error_info_injector<boost::lock_error> >'
what():  boost::lock_error

Code for parsing input in producer:

RtMidiIn *midiin = new RtMidiIn();
std::vector<unsigned char> message;
int nBytes, i;
double stamp;
m_queue=queue;        

// Check available ports.
unsigned int nPorts = midiin->getPortCount();
if ( nPorts == 0 ) {
    std::cout << "No ports available!\n";
    goto cleanup;
}

midiin->openPort( 1 );

// Don't ignore sysex, timing, or active sensing messages.
midiin->ignoreTypes( false, false, false );

// Install an interrupt handler function.
done = false;
(void) signal(SIGINT, finish);

// Periodically check input queue.
std::cout << "Reading MIDI from port ... quit with Ctrl-C.\n";
while ( !done ) {
  stamp = midiin->getMessage( &message );
  nBytes = message.size();
  if(nBytes>0){
    if((message.size()!=1)&&((int)message.at(0)!=137)){
            for ( i=0; i<nBytes; i++ )
            std::cout << "Byte " << i << " = " << (int)message[i] << ", ";
            if ( nBytes > 0 )
            std::cout << "stamp = " << stamp << std::endl;
            m_queue->Enqueue("asd");
    }
}
}

it breaks on the first time it encounters:

m_queue->Enqueue("asd");

When trying to execute:

boost::unique_lock<boost::mutex> lock(m_mutex);

Any help appreciated!

EDIT1:

This is the SynchronizedQueue object. The exception is thrown when calling Enqueue().

template <typename T>
class SynchronizedQueue
{
private:
    std::queue<T> m_queue;                      // Use STL queue to store data
    mutable boost::mutex m_mutex;                       // The mutex to synchronise on
    boost::condition_variable m_cond;       // The condition to wait for

public:

    // Add data to the queue and notify others
    void Enqueue(const T& data)
    {
        // Acquire lock on the queue
            boost::unique_lock<boost::mutex> lock(m_mutex);
        // Add the data to the queue
        m_queue.push(data);
            // Notify others that data is ready
        m_cond.notify_one();
        } // Lock is automatically released here

    // Get data from the queue. Wait for data if not available
    T Dequeue()
    {

        // Acquire lock on the queue
        boost::unique_lock<boost::mutex> lock(m_mutex);
        //lock();
        // When there is no data, wait till someone fills it.
        // Lock is automatically released in the wait and obtained 
        // again after the wait
        while (m_queue.size()==0) m_cond.wait(lock);

        // Retrieve the data from the queue
        T result=m_queue.front(); m_queue.pop();
        return result;
    } // Lock is automatically released here
};

Solution

  • most times, when I stumble over such an issue, it's that the mutex that got locked is already destroyed or wasn't constructed already. Are you sure, the queue, that you are passing to your parser, is already constructed, when the parser threads starts parsing? Or it might be, that the exit of a loop containing the queue as local variable stopped? Maybe you can do a quick test and add a d'tor to the queue and set a breakpoint there.

    regards Torsten