Added atomic guards to clear promises
And a specific thread to avoid useless race conditions
This commit is contained in:
parent
d1e031e8e2
commit
528593fa76
2 changed files with 35 additions and 7 deletions
|
|
@ -27,10 +27,10 @@
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
#include "Debug.h"
|
#include "Debug.h"
|
||||||
#include "Oversampler.h"
|
#include "Oversampler.h"
|
||||||
|
#include "AtomicGuard.h"
|
||||||
#include "absl/types/span.h"
|
#include "absl/types/span.h"
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <mutex>
|
|
||||||
#include <sndfile.hh>
|
#include <sndfile.hh>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
using namespace std::chrono_literals;
|
using namespace std::chrono_literals;
|
||||||
|
|
@ -149,12 +149,28 @@ void sfz::FilePool::setPreloadSize(uint32_t preloadSize) noexcept
|
||||||
this->preloadSize = preloadSize;
|
this->preloadSize = preloadSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void sfz::FilePool::tryToClearPromises()
|
||||||
|
{
|
||||||
|
AtomicDisabler disabler { canAddPromisesToClear };
|
||||||
|
|
||||||
|
while (addingPromisesToClear)
|
||||||
|
std::this_thread::sleep_for(1ms);
|
||||||
|
|
||||||
|
promisesToClear.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void sfz::FilePool::clearingThread()
|
||||||
|
{
|
||||||
|
while (!quitThread) {
|
||||||
|
tryToClearPromises();
|
||||||
|
std::this_thread::sleep_for(50ms);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void sfz::FilePool::loadingThread() noexcept
|
void sfz::FilePool::loadingThread() noexcept
|
||||||
{
|
{
|
||||||
FilePromisePtr promise;
|
FilePromisePtr promise;
|
||||||
while (!quitThread) {
|
while (!quitThread) {
|
||||||
promisesToClean.clear();
|
|
||||||
|
|
||||||
if (emptyQueue) {
|
if (emptyQueue) {
|
||||||
while(promiseQueue.try_dequeue(promise)) {
|
while(promiseQueue.try_dequeue(promise)) {
|
||||||
// We're just dequeuing
|
// We're just dequeuing
|
||||||
|
|
@ -197,11 +213,16 @@ void sfz::FilePool::clear()
|
||||||
emptyFileLoadingQueues();
|
emptyFileLoadingQueues();
|
||||||
preloadedFiles.clear();
|
preloadedFiles.clear();
|
||||||
temporaryFilePromises.clear();
|
temporaryFilePromises.clear();
|
||||||
promisesToClean.clear();
|
promisesToClear.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void sfz::FilePool::cleanupPromises() noexcept
|
void sfz::FilePool::cleanupPromises() noexcept
|
||||||
{
|
{
|
||||||
|
AtomicGuard guard { addingPromisesToClear };
|
||||||
|
|
||||||
|
if (!canAddPromisesToClear)
|
||||||
|
return;
|
||||||
|
|
||||||
FilePromisePtr promise;
|
FilePromisePtr promise;
|
||||||
// Remove stuff from the filled queue and put them in a linear storage
|
// Remove stuff from the filled queue and put them in a linear storage
|
||||||
while (filledPromiseQueue.try_dequeue(promise))
|
while (filledPromiseQueue.try_dequeue(promise))
|
||||||
|
|
@ -211,7 +232,7 @@ void sfz::FilePool::cleanupPromises() noexcept
|
||||||
auto sentinel = temporaryFilePromises.end() - 1;
|
auto sentinel = temporaryFilePromises.end() - 1;
|
||||||
while (promiseIterator != temporaryFilePromises.end()) {
|
while (promiseIterator != temporaryFilePromises.end()) {
|
||||||
if (promiseIterator->use_count() == 1) {
|
if (promiseIterator->use_count() == 1) {
|
||||||
promisesToClean.push_back(*promiseIterator);
|
promisesToClear.push_back(*promiseIterator);
|
||||||
std::iter_swap(promiseIterator, sentinel);
|
std::iter_swap(promiseIterator, sentinel);
|
||||||
sentinel--;
|
sentinel--;
|
||||||
temporaryFilePromises.pop_back();
|
temporaryFilePromises.pop_back();
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@
|
||||||
#include "Defaults.h"
|
#include "Defaults.h"
|
||||||
#include "LeakDetector.h"
|
#include "LeakDetector.h"
|
||||||
#include "AudioBuffer.h"
|
#include "AudioBuffer.h"
|
||||||
|
#include "AudioSpan.h"
|
||||||
#include "SIMDHelpers.h"
|
#include "SIMDHelpers.h"
|
||||||
#include "ghc/fs_std.hpp"
|
#include "ghc/fs_std.hpp"
|
||||||
#include <absl/container/flat_hash_map.h>
|
#include <absl/container/flat_hash_map.h>
|
||||||
|
|
@ -61,7 +62,7 @@ struct FilePromise
|
||||||
AudioBufferPtr preloadedData {};
|
AudioBufferPtr preloadedData {};
|
||||||
std::unique_ptr<AudioBuffer<float>> fileData {};
|
std::unique_ptr<AudioBuffer<float>> fileData {};
|
||||||
float sampleRate { config::defaultSampleRate };
|
float sampleRate { config::defaultSampleRate };
|
||||||
std::atomic<int> availableFrames { 0 };
|
std::atomic_size_t availableFrames { 0 };
|
||||||
std::atomic<bool> dataReady { false };
|
std::atomic<bool> dataReady { false };
|
||||||
Oversampling oversamplingFactor { config::defaultOversamplingFactor };
|
Oversampling oversamplingFactor { config::defaultOversamplingFactor };
|
||||||
};
|
};
|
||||||
|
|
@ -92,6 +93,7 @@ public:
|
||||||
{
|
{
|
||||||
for (int i = 0; i < config::numBackgroundThreads; ++i)
|
for (int i = 0; i < config::numBackgroundThreads; ++i)
|
||||||
fileLoadingThreadPool.emplace_back( &FilePool::loadingThread, this );
|
fileLoadingThreadPool.emplace_back( &FilePool::loadingThread, this );
|
||||||
|
fileLoadingThreadPool.emplace_back( &FilePool::clearingThread, this );
|
||||||
}
|
}
|
||||||
|
|
||||||
~FilePool()
|
~FilePool()
|
||||||
|
|
@ -200,6 +202,8 @@ public:
|
||||||
private:
|
private:
|
||||||
fs::path rootDirectory;
|
fs::path rootDirectory;
|
||||||
void loadingThread() noexcept;
|
void loadingThread() noexcept;
|
||||||
|
void clearingThread();
|
||||||
|
void tryToClearPromises();
|
||||||
|
|
||||||
moodycamel::BlockingConcurrentQueue<FilePromisePtr> promiseQueue { config::maxVoices };
|
moodycamel::BlockingConcurrentQueue<FilePromisePtr> promiseQueue { config::maxVoices };
|
||||||
moodycamel::BlockingConcurrentQueue<FilePromisePtr> filledPromiseQueue { config::maxVoices };
|
moodycamel::BlockingConcurrentQueue<FilePromisePtr> filledPromiseQueue { config::maxVoices };
|
||||||
|
|
@ -211,7 +215,10 @@ private:
|
||||||
std::atomic<int> threadsLoading { 0 };
|
std::atomic<int> threadsLoading { 0 };
|
||||||
|
|
||||||
std::vector<FilePromisePtr> temporaryFilePromises;
|
std::vector<FilePromisePtr> temporaryFilePromises;
|
||||||
std::vector<FilePromisePtr> promisesToClean;
|
std::vector<FilePromisePtr> promisesToClear;
|
||||||
|
std::atomic<bool> addingPromisesToClear;
|
||||||
|
std::atomic<bool> canAddPromisesToClear;
|
||||||
|
|
||||||
absl::flat_hash_map<absl::string_view, PreloadedFileHandle> preloadedFiles;
|
absl::flat_hash_map<absl::string_view, PreloadedFileHandle> preloadedFiles;
|
||||||
std::vector<std::thread> fileLoadingThreadPool { };
|
std::vector<std::thread> fileLoadingThreadPool { };
|
||||||
LEAK_DETECTOR(FilePool);
|
LEAK_DETECTOR(FilePool);
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue