Added atomic guards to clear promises

And a specific thread to avoid useless race conditions
This commit is contained in:
Paul Ferrand 2019-12-22 19:12:17 +01:00
parent d1e031e8e2
commit 528593fa76
2 changed files with 35 additions and 7 deletions

View file

@ -27,10 +27,10 @@
#include "Config.h"
#include "Debug.h"
#include "Oversampler.h"
#include "AtomicGuard.h"
#include "absl/types/span.h"
#include <chrono>
#include <memory>
#include <mutex>
#include <sndfile.hh>
#include <thread>
using namespace std::chrono_literals;
@ -149,12 +149,28 @@ void sfz::FilePool::setPreloadSize(uint32_t preloadSize) noexcept
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
{
FilePromisePtr promise;
while (!quitThread) {
promisesToClean.clear();
if (emptyQueue) {
while(promiseQueue.try_dequeue(promise)) {
// We're just dequeuing
@ -197,11 +213,16 @@ void sfz::FilePool::clear()
emptyFileLoadingQueues();
preloadedFiles.clear();
temporaryFilePromises.clear();
promisesToClean.clear();
promisesToClear.clear();
}
void sfz::FilePool::cleanupPromises() noexcept
{
AtomicGuard guard { addingPromisesToClear };
if (!canAddPromisesToClear)
return;
FilePromisePtr promise;
// Remove stuff from the filled queue and put them in a linear storage
while (filledPromiseQueue.try_dequeue(promise))
@ -211,7 +232,7 @@ void sfz::FilePool::cleanupPromises() noexcept
auto sentinel = temporaryFilePromises.end() - 1;
while (promiseIterator != temporaryFilePromises.end()) {
if (promiseIterator->use_count() == 1) {
promisesToClean.push_back(*promiseIterator);
promisesToClear.push_back(*promiseIterator);
std::iter_swap(promiseIterator, sentinel);
sentinel--;
temporaryFilePromises.pop_back();

View file

@ -26,6 +26,7 @@
#include "Defaults.h"
#include "LeakDetector.h"
#include "AudioBuffer.h"
#include "AudioSpan.h"
#include "SIMDHelpers.h"
#include "ghc/fs_std.hpp"
#include <absl/container/flat_hash_map.h>
@ -61,7 +62,7 @@ struct FilePromise
AudioBufferPtr preloadedData {};
std::unique_ptr<AudioBuffer<float>> fileData {};
float sampleRate { config::defaultSampleRate };
std::atomic<int> availableFrames { 0 };
std::atomic_size_t availableFrames { 0 };
std::atomic<bool> dataReady { false };
Oversampling oversamplingFactor { config::defaultOversamplingFactor };
};
@ -92,6 +93,7 @@ public:
{
for (int i = 0; i < config::numBackgroundThreads; ++i)
fileLoadingThreadPool.emplace_back( &FilePool::loadingThread, this );
fileLoadingThreadPool.emplace_back( &FilePool::clearingThread, this );
}
~FilePool()
@ -200,6 +202,8 @@ public:
private:
fs::path rootDirectory;
void loadingThread() noexcept;
void clearingThread();
void tryToClearPromises();
moodycamel::BlockingConcurrentQueue<FilePromisePtr> promiseQueue { config::maxVoices };
moodycamel::BlockingConcurrentQueue<FilePromisePtr> filledPromiseQueue { config::maxVoices };
@ -211,7 +215,10 @@ private:
std::atomic<int> threadsLoading { 0 };
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;
std::vector<std::thread> fileLoadingThreadPool { };
LEAK_DETECTOR(FilePool);