I'm writing a media player based on FFmpeg and I have a design issue. My code calls a function to render video frames at irregular intervals using SDL's SDL_AddTimer function. My problem is this, if I want to perform garbage collection when one video ends (or playback is stopped) and another starts, how can I ensure that I have no more timers in the queue or in the middle of execution as to avoid accessing an object that suddenly has been freed.
There's a lot of different ways to solve your problem based on your specific implementation. Few basic ideas can be:
Define a boolean that specifies if the player is running (true = running, false = not)
Before each call related to the player, check that variable and if its false (the player is stopped), close the function (immediately return)
Then, you call removeTimer
and you set the variable to false to close the player.
However, because addTimer
is a function that creates threads, there can be sometimes race conditions(what you called "the middle of execution"). It's one of the main problem when you use threads.
You need to find and fix those by using tools such as mutexes, semaphores, ... The choice of those tools greatly depends on the strategy you want to implement to avoid those race conditions.
So, there is no generic solution. If performance is not a concern, you can use that simple "one-lock" solution. It's a basic implementation of the "critical section" strategy. It prevents some pieces of code (closing player and running critical sound-related calls) to run simultaneously.
#include <pthread.h>
#include <stdbool.h>
pthread_mutex_t mutex;
bool isRunning;
int timerID;
void timerCallback(){
// do some computations
pthread_mutex_lock(&mutex);
// that critical section, defined here will never
// (thank to the mutex) occur at the same time at
// the critical section in the close method
if(isRunning){
// do critical calls
}
else{
// do nothing
}
pthread_mutex_unlock(&mutex);
// do some other computations
}
void init(){
pthread_mutex_init(&mutex, NULL);
isRunning = true;
startTimers();
}
void close(){
pthread_mutex_lock(&mutex);
// that critical section, defined here will never
// (thank to the mutex) occur at the same time at
// the critical section in the timerCallback method
SDL_RemoveTimer(timerID);
isRunning = false;
pthread_mutex_unlock(&mutex);
pthread_mutex_destroy(&mutex);
}
Of course, I cannot explain all the race-condition avoidance strategies in a simple stackoverflow post. If you need to improve performance, you should define precisely what's your concurrency issue for your code and choose a right strategy.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With