tags:

views:

118

answers:

3

I've got a wrapper around a std::deque that I'm using to queue up audio data (coming in blocks via libavcodec, if that matters).

This is the function that takes a buffer of 16-bit data and adds it to the deque

void AVAudioBuffer::enqueue(int16_t* src, size_t num, double pts) {
  // Save current size of buffer
  size_t size = data_buffer_.size();

  lock();
  data_buffer_.insert(data_buffer_.end(), src, src+num);
  unlock();

 // Push PTS value onto queue
 if (pts != AV_NOPTS_VALUE) {
   pts_values_.push_back(pair<int,double>(size, pts));
  }
}

Definitions of lock/unlock:

void   lock()     { SDL_mutexP(mute_access_);     }
void unlock()     { SDL_mutexV(mute_access_);     }

My problem is, when the data_buffer_.insert statement is included in the code, the thread this function is in will execute once and then lockup. If I remove the code, it works. I tried replace the insert with a manual iteration of the src data, calling push_back() for each element, and this too causes the thread to lock.

Is this a valid way to append data to a deque? I tried it in a test program and it seemed to work fine, and the documentation seems to imply that it's OK. Why would this cause my thread to die?

Updated info: Added error messages for when locking/unlocking fail, and they both succeed just fine. I instrumented them to verify they're being executed in pairs, and they are. It's got to be something with the deque::insert call that's messing things up, I can remove it and things get moving again.

Update: I found the problem, I refactored the code and missed a constant so the dequeue was always checking as full, causing a loop =(

A: 

sounds like you need some thread locking. If another thread is reading (and hence updating) from the queue then you gotta lock it

oops - there is a lock there. My guess is that the lock is not working or that the reader is not locking

Does the reader thread lock too? Are you sure the lock is actually locking?

pm100
+1  A: 

That method of inserting into a deque is perfectly valid.

The source of your lockup is likely in the locking itself. All accesses to data_buffer_ should be synchronized (both read and write), including the call to data_buffer_.size(). If one thread reads from data_buffer_ while another thread writes to it, you can get random, undefined behavior.

If, after fixing that, it is still locking up, look for mismatched lock()/unlock() pairs or deadlocks. I'm also assuming you are using atomic locks.

Looking at your updated code, you should also synchronize accesses to pts_values_.

Jason Govig
That's what I was curious about, guess in the absence of that being a bad call, I'll just have to dig through to figure out where it's locking up at.
gct
+1  A: 

Since STL usage is fine as shown, I would suggest looking closer at the synchronization. The SDL mutex functions return -1 on error. Put a check for that into the lock() and unlock() and raise an exception, for example. You can log a thread ID on the entry into those functions too.

I'd also check that the input values are correct - make num does not overrun the input buffer.

A plug for good C++ techniques - get into habit of using RAII for lock management. This is what C++ destructors were invented for :)

Nikolai N Fetissov
Added error messages if the status for either is -1, and it looks like both the lock and unlock are working fine.
gct