2

我有一个围绕 std::deque 的包装器,我用它来排队音频数据(如果重要的话,通过 libavcodec 进入块)。

这是获取 16 位数据缓冲区并将其添加到双端队列的函数

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 调用搞砸了,我可以删除它,然后事情又开始了。

更新:我发现了问题,我重构了代码并错过了一个常量,所以出队总是检查为满,导致循环 =(

4

3 回答 3

1

这种插入双端队列的方法是完全有效的。

锁定的根源可能在于锁定本身。所有对 data_buffer_ 的访问都应该同步(读取和写入),包括对 data_buffer_.size() 的调用。如果一个线程从 data_buffer_ 读取,而另一个线程写入它,您可能会得到随机的、未定义的行为。

如果在修复该问题后仍处于锁定状态,请查找不匹配的 lock()/unlock() 对或死锁。我还假设您正在使用原子锁。

查看更新后的代码,您还应该同步对 pts_values_ 的访问。

于 2010-01-13T02:13:18.777 回答
1

由于 STL 的使用很好,如图所示,我建议仔细查看同步。SDL 互斥函数返回-1错误。lock()例如,对and进行检查unlock()并引发异常。您也可以在这些函数的条目上记录线程 ID。

我还要检查输入值是否正确 - makenum不会超出输入缓冲区。

优秀 C++ 技术的插件 - 养成使用RAII进行锁管理的习惯。这就是 C++ 析构函数的发明目的:)

于 2010-01-13T02:25:21.530 回答
0

听起来你需要一些线程锁定。如果另一个线程正在从队列中读取(并因此更新),那么你必须锁定它

哎呀-那里有一把锁。我的猜测是锁不起作用或阅读器没有锁定

阅读器线程是否也锁定?您确定锁实际上是锁定的吗?

于 2010-01-13T01:53:05.360 回答