我有一个围绕std :: deque的包装器,我正在使用它来排队音频数据(通过libavcodec进入块,如果这很重要的话)。
这是一个获取16位数据缓冲区并将其添加到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));
}
}
锁定/解锁的定义:
void lock() { SDL_mutexP(mute_access_); }
void unlock() { SDL_mutexV(mute_access_); }
我的问题是,当代码中包含data_buffer_.insert语句时,此函数所在的线程将执行一次然后锁定。如果我删除代码,它的工作原理。我尝试用src数据的手动迭代替换插入,为每个元素调用push_back(),这也导致线程锁定。
这是将数据附加到双端队列的有效方法吗?我在一个测试程序中尝试过它似乎工作正常,文档似乎暗示它没关系。为什么这会导致我的线程死亡?
更新信息:添加了锁定/解锁失败时的错误消息,它们都成功了。我指示他们验证他们是成对执行的,他们是。它必须是deque :: insert调用的东西搞砸了,我可以删除它,事情再次发生变化。
更新:我发现了问题,我重构了代码并错过了一个常量,所以dequeue总是检查为full,导致循环=(
答案 0 :(得分:1)
插入双端队列的方法完全有效。
锁定的来源很可能是锁定本身。对data_buffer_的所有访问都应该同步(读取和写入),包括对data_buffer_.size()的调用。如果一个线程从data_buffer_读取而另一个线程写入它,则可以获得随机的,未定义的行为。
如果在修复之后仍然锁定,请查找不匹配的lock()/ unlock()对或死锁。我还假设你正在使用原子锁。
查看更新后的代码,还应该同步访问pts_values _。
答案 1 :(得分:1)
由于如图所示STL使用情况良好,我建议仔细研究同步。 SDL互斥锁函数在出错时返回-1
。例如,检查一下lock()
和unlock()
并引发异常。您也可以将条目上的线程ID记录到这些函数中。
我还要检查输入值是否正确 - make num
不会超出输入缓冲区。
用于良好C ++技术的插件 - 养成使用RAII进行锁管理的习惯。这就是C ++析构函数的发明:)
答案 2 :(得分:0)
听起来你需要一些线程锁定。如果另一个线程正在从队列中读取(并因此更新),那么你必须将其锁定
哎呀 - 那里有锁。我的猜测是锁没有工作或读者没有锁定读者线程也锁定了吗?你确定锁实际上是锁定的吗?