render: dedicate thread to audio production

Prevents audio from getting stalled behind slow video jobs
This commit is contained in:
itsmattkc
2022-05-30 22:11:06 -07:00
parent ca26f023f2
commit 44d81f6b00
3 changed files with 49 additions and 24 deletions
+36 -19
View File
@@ -29,52 +29,67 @@ ThreadPool::ThreadPool(unsigned threads, QObject *parent) :
threads = std::thread::hardware_concurrency();
}
available_count_ = threads;
for (unsigned i = 0; i < threads; i += 1) {
worker_threads_.emplace_back(std::bind(&ThreadPool::thread_exec, this));
worker_threads_.emplace_back(std::bind(&ThreadPool::thread_exec, this, &tasks_, &task_mutex_, &cond_));
}
// Make single reserved thread for high priority tasks (usually audio) so they don't get stuck
// behind a lot of slow tasks
high_thread_ = std::thread(std::thread(std::bind(&ThreadPool::thread_exec, this, &high_tasks_, &high_mutex_, &high_cond_)));
}
void ThreadPool::AddTicket(RenderTicketPtr ticket, RenderTicketPriority priority)
{
std::lock_guard<std::mutex> lock(task_mutex_);
if (priority == RenderTicketPriority::kHigh) {
tasks_.emplace_front(std::move(ticket));
std::lock_guard<std::mutex> lock(high_mutex_);
high_tasks_.emplace_back(std::move(ticket));
high_cond_.notify_one();
} else {
std::lock_guard<std::mutex> lock(task_mutex_);
tasks_.emplace_back(std::move(ticket));
cond_.notify_one();
}
cond_.notify_one();
}
bool ThreadPool::RemoveTicket(RenderTicketPtr ticket)
{
std::lock_guard<std::mutex> lock(task_mutex_);
const auto it = std::find(tasks_.begin(), tasks_.end(), ticket);
if (it == tasks_.end()) {
return false;
{
std::lock_guard<std::mutex> lock(task_mutex_);
const auto it = std::find(tasks_.begin(), tasks_.end(), ticket);
if (it != tasks_.end()) {
tasks_.erase(it);
return true;
}
}
tasks_.erase(it);
return true;
{
std::lock_guard<std::mutex> lock(high_mutex_);
const auto it = std::find(high_tasks_.begin(), high_tasks_.end(), ticket);
if (it != high_tasks_.end()) {
high_tasks_.erase(it);
return true;
}
}
return false;
}
void ThreadPool::thread_exec()
void ThreadPool::thread_exec(std::deque<TaskType> *queue, std::mutex *mutex, std::condition_variable *cond)
{
while (true) {
TaskType task;
{
std::unique_lock<std::mutex> lock(task_mutex_);
cond_.wait(lock, [this]{ return this->end_threadp_ || !this->tasks_.empty(); });
std::unique_lock<std::mutex> lock(*mutex);
cond->wait(lock, [this, queue]{ return this->end_threadp_ || !queue->empty(); });
if (this->end_threadp_ && this->tasks_.empty()) {
if (this->end_threadp_ && queue->empty()) {
break;
}
task = std::move(tasks_.front());
tasks_.pop_front();
task = std::move(queue->front());
queue->pop_front();
}
RunTicket(task);
@@ -85,10 +100,12 @@ ThreadPool::~ThreadPool()
{
end_threadp_ = true;
cond_.notify_all();
high_cond_.notify_all();
for (auto &e : worker_threads_) {
e.join();
}
high_thread_.join();
}
}
+8 -1
View File
@@ -49,13 +49,20 @@ public:
virtual ~ThreadPool() override;
private:
void thread_exec();
void thread_exec(std::deque<TaskType> *queue, std::mutex *mutex, std::condition_variable *cond);
std::vector<std::thread> worker_threads_;
std::deque<TaskType> tasks_;
std::mutex task_mutex_;
std::condition_variable cond_;
std::thread high_thread_;
std::deque<TaskType> high_tasks_;
std::mutex high_mutex_;
std::condition_variable high_cond_;
std::atomic_bool end_threadp_{false};
std::atomic_int available_count_;
};
+5 -4
View File
@@ -1492,10 +1492,11 @@ void ViewerWidget::PlaybackTimerUpdate()
}
if (IsPlaying()) {
int count = 0;
for (int i=display_widget_->queue()->size(); i<DeterminePlaybackQueueSize(); i++) {
RequestNextFrameForQueue();
count++;
while (queue_watchers_.size() < DeterminePlaybackQueueSize()) {
if (!RequestNextFrameForQueue()) {
// Prevent infinite loop
break;
}
}
}