开发播放器等数据量大的程序,需要多线程实现线程安全的缓冲区。一个线程读磁盘或网络数据,另外线程对数据进行解码或其他处理,缓存其实是一个数据传输通道,类似硬件里面的FIFO。程序需要防止线程的数据完整性,还要支持数据空和满的控制。
下面是我使用的一个具体程序,使用正常,至于原理大家看操作系统有关书籍吧。主要用到锁、信号量等。
//cond.h定义线程安全使用的信号和互锁。
#include <pthread.h>
#include <time.h>
class Cond
{
public:
Cond();
~Cond();
//上锁
int Lock();
//解锁
int Unlock();
int Wait(); //等待信号
int TimedWait(int second);
int Signal(); //通知
int Broadcast();//广播通知
private:
pthread_mutex_t m_mutex;
pthread_cond_t m_cond;
#endif
};
//cond.cpp
#include "Cond.h"
Cond::Cond()
{
pthread_mutex_init(&m_mutex, NULL);
pthread_cond_init(&m_cond, NULL);
}
Cond::~Cond()
{
pthread_mutex_destroy(&m_mutex);
pthread_cond_destroy(&m_cond);
}
//加锁
int Cond::Lock()
{
return pthread_mutex_lock(&m_mutex);
}
//解锁
int Cond::Unlock()
{
return pthread_mutex_unlock(&m_mutex);
}
int Cond::Wait()
{
int ret = pthread_cond_wait(&m_cond, &m_mutex);
return ret;
}
int Cond::TimedWait(int second)
{
struct timespec abstime;
clock_gettime(CLOCK_REALTIME, &abstime);
abstime.tv_sec += second;
return pthread_cond_timedwait(&m_cond, &m_mutex, &abstime);
}
int Cond::Signal()
{
int ret = pthread_cond_signal(&m_cond);
return ret;
}
//唤醒所有睡眠线程
int Cond::Broadcast()
{
return pthread_cond_broadcast(&m_cond);
}
下面是具体使用。
Cond *mConditon_Audio;
std::list<AVPacket> mAudioPacktList; //音频压缩包
bool inputAudioQuene( AVPacket &pkt) //读取压缩视频文件后得到的数据音频包
{ //复制音频数据包
if (av_packet_ref(const_cast<AVPacket *>(&mAudioStream->attached_pic),&pkt)<0)
{
return false;
}
mConditon_Audio->Lock();
while(mAudioPacktList.size()>MAX_AUDIO_SIZE) //判断是否读取包是否满
{ mConditon_Audio->Wait();}
mAudioPacktList.push_back(pkt);
mConditon_Audio->Signal();
mConditon_Audio->Unlock();
return true;
}
void clearAudioQuene()
{
mConditon_Audio->Lock();
for (AVPacket pkt : mAudioPacktList)
{
av_packet_unref(&pkt);
}
mAudioPacktList.clear();
mConditon_Audio->Unlock();
}
使用FIFO里面的packet
mConditon_Audio->Lock();
while(mAudioPacktList.size() <= 0) //判断是否FIFO是否读空了
{
mConditon_Audio->Unlock();
mConditon_Audio->Wait();
}
AVPacket packet = mAudioPacktList.front(); //没有空我们可以读出
mAudioPacktList.pop_front();
mConditon_Audio->Unlock();
mConditon_Audio->Signal(); //读出后可以有空间,FIFO又可以读入