🕌

2024年のオーディオアプリケーション開発技術の動向に関する私的見解 (4)

2024/08/09に公開

当初の目的だったCOSCUP 2024セッション資料の肥やしとして書いていた、このシリーズはこれでひと区切りとしたい。見出しがちょっと主語でかい気もするけど、まあまあ妥当な話を書いていると思うのでこれでいくことにした。

COSCUP2024のスライドはspeakerdeckで公開しているので興味ある人はどうぞ。

https://speakerdeck.com/atsushieno/coscup2024-catching-up-trends-in-audio-app-development

C++低レベルオーディオ処理の最前線

リアルタイムオーディオ処理には、原則のようなものがある。たとえばスレッドのロックは使用しない、リアルタイムスレッドでメモリは確保しない、といったものだ。古典的な文献 time waits for nothing がよく言及される:

http://www.rossbencina.com/code/real-time-audio-programming-101-time-waits-for-nothing

これらの大原則は大きく変化していないが、そこから生じた派生原則のようなものは、実はC++言語の進化やアルゴリズムのレベルでのイノベーションを経て、現在でもいろいろな変化がある。

たとえば「メモリを確保してはならない」の原則からは、「newや動的メモリ確保するコンテナ操作を使わない」という派生原則が出てくるが、メモリを事前に確保するタイプのアロケーターをstd::pmr::set_default_resource()で指定すると、その範囲でメモリの動的確保が回避できている限り、問題ではなくなる。std::pmrはC++17で導入されたので、そろそろ問題なく使えるだろう。ADC '22でstd::pmrが紹介されたセッションでは、libc++/clangではまだexperimental扱いだったという話が出ている:

https://www.youtube.com/watch?v=h-A4a-pYtoc

他にもたとえばatomic shared pointerは新しい技術の話題として挙げられるだろう。ロックフリーでnon-atomicな程度に複雑なデータ構造にアクセスしようとすると、割と面倒な問題になる(フィルターを実装しようとしてcoeffみたいなものを表現するとすぐstructになってしまう、といえば必要性があることはわかってもらえると思う)。std::shared_ptr<T>をatomicで操作しようとすると、ロックが必要になってしまう。std::shared_ptr<T>はオブジェクトが不要になったときに解放処理を行わなければならないので、これが素朴にオーディオスレッド上で行われてはならない。かといって外で解放しつつ、オーディオスレッドではポインタが潜在的に使われているとなると、dangling pointerになってしまう。C++20にはstd::atomic<std::shared_ptr<T>>が導入されたが、これはロックフリーではなく、またclang++ではこれを書いている2024年7月時点でも未実装だ。これに相当するもの(つまりstd::でないatomic shared pointer)を自前で実装している人たちが何人かいて、それについてはこのCppCon 2023のセッションが詳しい(2022にもこれに先行するセッションがあるのだけど、後発のこっちのほうが詳しいのでこっちだけ出しておく):

https://www.youtube.com/watch?v=lNPZV9Iqo3U

FacebookのFollyなどが実装例として挙げられるのだけど、IntelやArmのDWCAS命令に依存して実現したり(RISC-Vにはそれが無いのでどうするの?みたいな話がある)、64ビットの整数の24ビットだけを実際のアドレス、残りの8ビットを管理情報扱いしてatomic操作するsplit reference countという方式を使ったり、といったアプローチが採られていた。だいぶややこしい設計だし、危ういところがあるので、このセッションではdeferred reclamationという別の手法で解決している。

このatomic shared pointerを実現する手段としても登場するのだけど、メモリの解放を直ちに行わずに解放キューに蓄積しておいて後で遅延解放する、いわゆるdeferred reclamationを活用するアプローチがここ数年で(?)流行っているようだ。 やっていることはmarkingとsweepingを分離したGCのlock freeなバージョンと考えてよい(lock freeではあるけどwait freeではない、みたいな話もある)。

deferred reclamationは他にも利用される場面があって、現在はC++26に入ろうとしているhazard pointersが計画されている。

オーディオ開発には、C++標準でclang++が実装していないような機能が必要になるような場面が、こんな感じでちょいちょい出てくる。

Discussion