Roger Larsson writes:
> This can easily be avoided by making these
'free-running' threads wait
> on an event that has the right frequency, e.g. a counting semaphore
> that is incremented by the output module each time a block is processed.
> This way you can eleminate all buffering between the threads, and
> you get a system that is as deterministic as e.g. JACK.
Easily avoided? By adding semaphores and more? The
point is that you can
not keep it as simple as pipe in pipe out. By adding semaphores the push
model is already more complex that the call back.
All the high level synchronisation functions such as poll(), select(),
pipes etc. are ultimately based on primitives such as semaphores and
condition variables. If you use these primitives directly (in the
implementation, not in the API - the user doesn't have to see them)
you can do things such as having a thread scheduled when all its
inputs are available, and then there is no need to analyse the
conection graph an plan ahead as JACK does. What you get is a
completely determinisic 'push-API' system.
OK, but you did not mention simple - is it also as
simple as JACK?
Implentation-wise, a lot simpler in fact. For the user (application
code writer) about the same. JACK looks simple because you don't see
what's happening behind the scenes, you only see the callback API.
By all this I don't want to leave the impression that I dislike JACK or
think it's badly written, on the contrary I think it's a high-quality,
and beautiful system, and it does a great service to the Linux audio
world.
The one thing I regret about JACK is that really tries to make things
*to* simple for the application developer, and thereby excludes some
possibilities that would come in handy.
The thread that calls the user's callback function is completely
hidden, and so it can wait only for the trigger form jackd and nothing
else. As a consequence you can't use it to communicate safely with your
callback which would be easy if the thread and the synchronisation
mechanism were visible.
--
FA