LoginSignup
11
7

More than 5 years have passed since last update.

Rustでも(そこそこ)安全なグローバルインスタンスを使いたい

Last updated at Posted at 2017-12-14

同じ記事を別のカレンダーに登録できないことに気づいて必死にネタを探しました。

うちのソフトウェアで必要に駆られて製作したappinstanceクレートを少し前に切り出して正式にpublishしたのでその紹介です。

つかいかた

appinstanceは主にアプリケーションの実行と同じライフタイムを持つ唯一のオブジェクト(つまりシングルトン)を定義するためのライブラリです。
appinstanceの実態はひとつのマクロなので、利用は次の一行を追加するだけでおしまいです。

AppInstance!(pub static instance: SelfObject = SelfObject::new());

staticとDrop

Rustにはすでにstaticというキーワードが存在しており、これを使うとアプリケーションと同等のライフタイムを持つデータを定義することが可能になっています。ただしこの定義はコンパイル時の定数を必要としており、HashMapやその他複雑な初期化を必要とするオブジェクトをstatic変数に持つことは難しい問題でした。
ここで、現在はlazy_staticを用いて解決する方法がとられると思います。これもマクロを提供するライブラリで、名前の通り遅延して評価されるstatic変数を定義するものです。その実体は、ポインタとOnceのペアの構造体で、初期状態ではポインタに0が格納されており、derefが呼ばれるとOnceにより初期化処理が一回だけ実行される、というものになっています。

lazy_staticを利用することでおおむねstaticがらみの問題は解決するのですが、lazy_staticにも難点があって、それはDrop::dropが実行されないという点です。ウィンドウシステムを利用するプログラムなどでRAIIを実装している場合、dropに重要な処理が書かれている場合があるので問題となることがあります。
ここでAppInstanceの出番になります。AppInstanceでは遅延して初期化すると同時にlibc::atexitにdropの処理を登録するようになっていて、これのおかげで(正常に終了すれば)生成と逆順にdropが呼ばれるようになります。dropの順番も定義されているので順番が重要なオブジェクトの解放も行うことが可能です。

欠点

AppInstanceはimmutableな参照しか返さないので可変である必要があるデータはAppInstanceにできないのですが、static mutがunsafeなのとCell/RefCellを使えば実現できなくもないのでこの用途のサポートはしないつもりです。

参考

rust - How do I create a global, mutable singleton? - Stack Overflow

11
7
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
7