SDL中带有几个子系统,其中有thread子系统。
前天想用c++重写一下ffplay.c,发现其中的回调函数在c++中不好用,还要继续学习。先练习了一下使用SDL_thread对队列进行操作。队列的同步问题是一个重点。
程序模拟对audio_queue和video_queue进行操作。
主进程发送包到audio_queue和video_queue,然后audio_thread和video_thread对audio_queue和video_queue分别进行处理。
为了防止在队列中积累的包数据太多,对于每个队列使用了初始值为max_queue_num的semaphore,每次投递一个包,对semaphore进行wait操作,每个thread取出一个包对semaphore进行post操作。保证了队列长队不超过10;
开始时由于对mutex的理解有误区,写的程序不稳定,修改后的终于成功了;
#include "simplayer.h"
#define MAX_QUEUE_SIZE 10
#include <list>
#include <windows.h>
using std::list;
FILE *trace;
list <int > audio_queue;
list <int > video_queue;
SDL_sem *pAudioSem;
SDL_sem *pVideoSem;
bool flag = true;
int AudioThread(void *arg)
{
SDL_mutex *pInternalMutex= (SDL_mutex *)arg;
fprintf(trace, "enter audio_queue thread /n");
int i = 0;
while(true)
{
int ret = SDL_LockMutex(pInternalMutex);
int size = 0;
if(ret == 0)
{
size = audio_queue.size();
SDL_UnlockMutex(pInternalMutex);
}
else
{
continue;
}
if(size == 0)
{
fprintf(trace,"audio_queue size is zero/n");
//break;
SDL_Delay(10);
continue;
}
ret = SDL_LockMutex(pInternalMutex);
if(ret == 0)
{
i = audio_queue.front();
audio_queue.pop_front();
SDL_SemPost(pAudioSem);
fprintf(trace,"in audio_queue get audio element is %d/n",i);
SDL_UnlockMutex(pInternalMutex);
if(i == 10000)
{
break;
}
}
else
{
fprintf(trace,"can't get lock in the audio_queue/n");
continue;
}
}
fprintf(trace,"leave thread audio_queue thread/n");
return i;
}
int VideoThread(void *arg)
{
SDL_mutex *pInternalMutex= (SDL_mutex *)arg;
fprintf(trace, "enter thread video_queue thread /n");
int i = 0;
while(true)
{
int ret = SDL_LockMutex(pInternalMutex);
int size = 0;
if(ret == 0)
{
size = video_queue.size();
SDL_UnlockMutex(pInternalMutex);
}
else
{
continue;
}
if(size == 0)
{
fprintf(trace, "video queue size is zero/n");
//break;
SDL_Delay(10);
continue;
}
ret = SDL_LockMutex(pInternalMutex);
if(ret == 0)
{
i = video_queue.front();
video_queue.pop_front();
SDL_SemPost(pVideoSem);
fprintf(trace,"in video_queue get video element is %d/n",i);
SDL_UnlockMutex(pInternalMutex);
if(i == 9999)
{
break;
}
}
else
{
fprintf(trace,"can't get lock in the video_queue/n");
continue;
}
}
fprintf(trace,"leave thread video_queue /n");
return i;
}
int main(int argc ,char **argv)
{
SDL_Init(SDL_INIT_EVERYTHING);
int audio_queue_cnt = 0;
int video_queue_cnt = 0;
int ret1= 0;
int ret2= 0;
int i = 0;
trace = fopen("trace.txt","wt");
SDL_mutex *pAudioMutex = NULL;
SDL_mutex *pVideoMutex = NULL;
pAudioMutex = SDL_CreateMutex();
pVideoMutex = SDL_CreateMutex();
pAudioSem = SDL_CreateSemaphore(MAX_QUEUE_SIZE);
pVideoSem = SDL_CreateSemaphore(MAX_QUEUE_SIZE);
SDL_Thread *audio_thread = SDL_CreateThread(AudioThread, pAudioMutex);
SDL_Thread *video_thread = SDL_CreateThread(VideoThread, pVideoMutex);
while(flag)
{
i++;
if(i%2 == 0)
{
//fprintf(trace, "before put an element to the audio_queue/n ");
SDL_SemWait(pAudioSem);
int ret = SDL_LockMutex(pAudioMutex);
if(ret == 0)
{
fprintf(trace, "put an element %d to the audio_queue..../n",i);
audio_queue.push_back(i);
SDL_UnlockMutex(pAudioMutex);
}
else
{
fprintf(trace, "can't get audio_queue lock/n");
}
//fprintf(trace, "after put an element to the audio_queue/n ");
}
else
{
//fprintf(trace, "before put an element to the video_queue/n ");
SDL_SemWait(pVideoSem);
int ret = SDL_LockMutex(pVideoMutex);
if(ret == 0)
{
fprintf(trace, "put an element %d to the video_queue.../n",i);
video_queue.push_back(i);
SDL_UnlockMutex(pVideoMutex);
}
else
{
fprintf(trace, "can't get video_queue lock/n");
}
//fprintf(trace, "after put an element to the video_queue/n ");
}
if(audio_queue.size() >MAX_QUEUE_SIZE || video_queue.size() > MAX_QUEUE_SIZE )
{
//Sleep(1000);
}
if(i == 10000)
{
flag = false;
}
}
SDL_WaitThread(audio_thread, &ret1);
fprintf(trace,"audio thread exit with value %d /n", ret1);
SDL_WaitThread(video_thread, &ret2);
fprintf(trace, "video thread exit with value %d /n", ret2);
SDL_DestroySemaphore(pAudioSem);
SDL_DestroySemaphore(pVideoSem);
system("pause");
return 0;
}
simPlay.h 中包含有常用的sdl.h