GithubHelp home page GithubHelp logo

farbot's Introduction

farbot

FAbian's Realtime Box o' Tricks

This is a collection of design patterns which can be used in realtime code. This library was introduced to the public at meeting C++ on 16th of November 2019.

This library and the containing design patterns were presented at meeting C++ 2019. You can find the slides here: https://hogliux.github.io/farbot/presentations/meetingcpp_2019/index.html

It contains the following realtime design patterns:

RealtimeObject

RealtimeObject<T, RealtimeObjectOptions> is a templated class with which you can share data of type T between non-realtime threads and a single realtime thread. Depending on the non-type template parameter option RealtimeObjectOptions either only the realtime or the non-realtime thread may mutate the data.

You can use it liked this:

struct BiquadCoeffecients  {  float b0, b1, b2, a1, a2; };
RealtimeObject<BiquadCoeffecients, RealtimeObjectOptions::nonRealtimeMutatable> biquadCoeffs;

/* called on realtime thread */
void processAudio (float* buffer)
{
    RealtimeObject<BiquadCoeffecients, RealtimeObjectOptions::nonRealtimeMutatable>::ScopedAccess<ThreadType::realtime> coeffs(biquadCoeffs);
    processBiquad (*coeffs, buffer);
}

/* called on non-realtime thread */
void changeBiquadParameters (BiquadCoeffecients newCoeffs)
{
    RealtimeObject<BiquadCoeffecients, RealtimeObjectOptions::nonRealtimeMutatable>::ScopedAccess<ThreadType::nonRealtime> coeffs(biquadCoeffs);
    *coeffs = newCoeffs;
}

where the ThreadType::Realtime/ThreadType::nonRealtime template parameter of the ScopedAccess class indicates if the thread requiring access to the data is a realtime thread or not.

Here is an example where only the realtime thread can mutate the data:

using FrequencySpectrum = std::array<float, 512>;
RealtimeObject<FrequencySpectrum, RealtimeObjectOptions::realtimeMutatable> mostRecentSpectrum;

/* called on realtime thread */
void processAudio (const float* buffer, size_t n) {
    RealtimeObject<FrequencySpectrum, RealtimeObjectOptions::realtimeMutatable>::ScopedAccess<ThreadType::realtime> freqSpec(mostRecentSpectrum);
    *freqSpec = calculateSpectrum (buffer, n);
}

/* called on non-realtime thread */
void updateSpectrumUIButtonClicked() {
    RealtimeObject<FrequencySpectrum, RealtimeObjectOptions::realtimeMutatable>::ScopedAccess<ThreadType::nonRealtime> recentSpectrum(mostRecentSpectrum);
    displaySpectrum(*recentSpectrum);
}

fifo

fifo is a versatile realtime-safe ringbuffer class which supports various types of fifos: you can choose the consumer/producer to either be accessed from a single or multiple thread. This need not be the same for the consumer and producer, for example, you could have a multi-producer, single-consumer fifo. This is controlled by the farbot::fifo_options::concurrency::single/farbot::fifo_options::concurrency::multiple template parameter.

In addition, you can also choose what happens on an underrun (during a pop) or an overrun (during a push). A fifo with farbot::fifo_options::full_empty_failure_mode::return_false_on_full_or_empty will return false on a push/pop if the fifo is full/empty respectively. A fifo with farbot::fifo_options::full_empty_failure_mode::overwrite_or_return_default will overwrite on full (pop) or return a default constructed element on empty (pop). Again, this option can be chosen independently for the consumer or producer. Note, that with the farbot::fifo_options::full_empty_failure_mode::overwrite_or_return_default option the ordering of the FIFO is lost when overrunning or underruning, i.e. newer elements may be returned before older elements in this case.

The fifo will never lock nor block. Additionally, depending on the above options the push/pop operation may be wait-free: if the consumer/producer is accessed from only a single thread or the consumer/producer uses overwrite_or_return_default then the pop/push will be wait-free respectively. Otherwise the perticular (i.e. push or pop) operation will not be wait-free.

Usage:

fifo<std::function<void()>*,
                  fifo_options::concurrency::single,
                  fifo_options::concurrency::multiple,
                  fifo_options::full_empty_failure_mode::return_false_on_full_or_empty,
                  fifo_options::full_empty_failure_mode::overwrite_or_return_default> my_fifo; // <- this fifo is wait-free on push and pop

fifo.push (mylambda);
std::function<void()>* almabda;
fifo.pop (alambda);

AsyncCaller

AsyncCaller is a class which contains a method called callAsync with which a lambda can be deferred to be processed on a non-realtime thread. This is useful to be able to execute potential non-realtime safe code on a realtime thread (like logging, or deallocations, ...).

Realtime traits

The farbot library also contains very limited type traits to check if a specific type is realtime movable/copyable. Currently this only works for trivially movable/copyable and a few STL containers.

farbot::is_realtime_copy_assignable, farbot::is_realtime_copy_constructable farbot::is_realtime_move_assignable, farbot::is_realtime_move_constructable

farbot's People

Contributors

hogliux avatar timart avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

farbot's Issues

fifo crashes if pos >= MAX_THREADS

Hi Fabian.
Thanks for all your great work !

I created an issue with tracktion_engine's "EngineInPlugin " that crashes Reaper on Windows after several [Alt+Tab]s.
Tracktion/tracktion_engine#115

It crashes on Farbot's :

if (pos >= MAX_THREADS)
{
assert (false);
// do something!
return tinfos.front().pos;
}

I found a workaround but I dont' know if it's a good idea :
I increase MAX_THREADS to 256 (rather than 64)

Let me know if you have a better solution ๐Ÿ˜ƒ
Thanks

RealtimeObject: identifier not found.

return RealtimeObject (false, std::forward<Args>(args)...);

RealtimeObject doesn't seem to be defined anywhere. There's a second reference to it in NonRealtimeMutatable.tcc with a similar use but without it the create methods are unusable and therefore it's impossible to pass arguments to T's constructor (AFAIK).

Maybe I've missed something?

ScopedAccess classes are unwieldy

To use a ScopedAccess object, you have to know its full type, which is pretty awkward to spell out, especially inside template classes:

using ScopedReader = typename farbot::RealtimeMutatable<Data<T>>::template ScopedAccess<false>;

The client has to remember what true and false mean, which isn't obvious. An enum class IsRealtime { no, yes }; instead of a plain bool would help greatly here, as would inner using declarations for ScopedReader and ScopedWriter.

Even better, though, would be to have a [[nodiscard]] auto scopedRead() const noexcept member function directly on the RealtimeMutatable class, so that the user can just do something like this.

// no need to utter the inner typename at all!
const auto reader = realtimeMutatable.scopedRead();
std::cout << *reader << '\n'; // or whatever other slow thing we're doing on the non-realtime thread

In C++17, guaranteed copy elision should mean that you can return one of these non-copyable ScopedAccess objects from a function like this.

fifo.tcc compile errors

When attempting to test fifo.hpp and fifo.tcc on macOS and windows 10 in a basic command line app, the compilers on both platforms fail on fifo.tcc line 194
std::vector slots = {};
macOS: error: expected member name or ';' after declaration specifiers
visual studio on Windows 10: error C2059: syntax error: '=', error C2334: unexpected token(s) preceding '{'; skipping apparent function body

Can't use realtime object in class templates

From what I can see realtime object does not work with class templates. This does not compile:

template<typename FloatType>
class Test
{
public:
    Test()
    {
        farbot::RealtimeObject<std::vector<FloatType>, farbot::RealtimeObjectOptions::nonRealtimeMutatable> obj;
        farbot::RealtimeObject<std::vector<FloatType>, farbot::RealtimeObjectOptions::nonRealtimeMutatable>::ScopedAccess<farbot::ThreadType::nonRealtime> t(obj);
        
        t->push_back(6.0);
    }
};

Why is this?

Worker Thread for AsyncCaller

I just took a look into this library (and watched the two videos on YouTube) but I can't find a good example on how to run the process function. In the video you said that it is possible to make the process thread run interleaved with audio thread? How exactly can I accomplish that?
Can you recommend any papers I can read about that topic? When I search on that topics, I tend to find a lot of stuff about writing the audio thread and the syncing mechanisms (like a fifo queue) but its very hard to find example for the consumer thread that is actually working the queue. Even though that may only be very few lines of code they are very important.

I hope you (or someone else of course) can help me with that.
Thanks in advance!

RealtimeMutatable::nonRealtimeAcquire loops indefinitely

control.store ((idx & INDEX_BIT) | BUSY_BIT | NEWDATA_BIT, std::memory_order_release);

It looks to me like realtimeRelease toggles the BUSY_BIT on, which means that subsequent calls to nonRealtimeAcquire will loop for ever, waiting for the busy bit to become unset.

I'm not convinced that the realtimeAcquire is correct either, shouldn't it set the busy bit?

fifo defaults wrongly labeled?

Hi Fabian,

thanks for this amazing work! If I may quote from the fifo.hpp

// single consumer, single producer
template <typename T,
          fifo_options::concurrency consumer_concurrency = fifo_options::concurrency::multiple,
          fifo_options::concurrency producer_concurrency = fifo_options::concurrency::multiple,
          fifo_options::full_empty_failure_mode consumer_failure_mode = fifo_options::full_empty_failure_mode::return_false_on_full_or_empty,
          fifo_options::full_empty_failure_mode producer_failure_mode = fifo_options::full_empty_failure_mode::return_false_on_full_or_empty,
          std::size_t MAX_THREADS = 64>

I find it hard to understand what the comment is supposed to tell me. Doesn't fifo<MyType> create a multi consumer, multi producer queue?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.