現在位置: ホーム / TinBlog / dispatch_queue_t と release

dispatch_queue_t と release

作者: h2 最終変更日時 2013年10月03日 22時56分 |
カテゴリー: ,
dispatch_queue_create を使うと、新しいスレッド実行用オブジェクト、dispatch_queue_t を作ることができる。だが、このオブジェクト、はたして使用後に release する必要があるのだろうか。現状のドキュメントだと、かなり悩ましいことになっているので、追求してみた。

そもそも、現時点(2013/10/03)のドキュメントによると、

Discussion
...(中略)...

When your application no longer needs the dispatch queue, it should release it with the dispatch_release function. Any pending blocks submitted to a queue hold a reference to that queue, so the queue is not deallocated until all pending blocks have completed.

----- ADC : Grand Central Dispatch (GCD) Reference

となっている。"should release"、つまり「dispatch_release() を使用して解放しなさい」だ。

ところが、ここで一つ困ったことが発生する。dispatch_queue_create() によって作成されるのは、dispatch_queue_t オブジェクトなのに対し、dispatch_release() が解放できるのは、dispatch_object_t オブジェクトだったりする。つまり、型が合わない

 

とはいえ、C関数レベルの話になると、じつは型が合わなくても受け付ける場合もあったりする。実例を挙げると、CFArray等のCoreFoundationに由来するオブジェクト群だ(実際、CFArrayCreate() にて生成される CFArrayRef オブジェクトに対して、対となるべき CFArrayRelease() なる関数は用意されていない)。これらCoreFoundation由来のオブジェクトは、一律 CFRelease() で解放してやることができる。これは、CFRelease() が受け取る CFTypeRef と、他のCoreFoundationオブジェクトとの間に、オブジェクト指向でいうところの親子関係が存在するためだ。Objective-Cと比較して、CFTypeRefNSObjectCFArrayNSArrayと置き換えてやれば、なぜこれが成立するかはわかるかと。

ARCの話が混ざり込むとややこしくなるので、とりあえずARC未使用下での話としています、あしからず。

 

話を戻して、「dispatch_queue_create() によって作成される型と dispatch_release() が解放できる型が一致しない」問題について。上の話からわかるように、型が不一致でも、CoreFoundationのように型自体に互換性があれば、解放することは可能なはずだ。

 

そこで、そもそも dispatch_queue_tdispatch_object_t の定義はどうなっているのか、ヘッダファイルの宣言を確認してみると。

 

dispatch_object_t

-->> object.h, 49行目で ”OS_OBJECT_DECL(dispatch_object);” と宣言されている。

dispatch_queue_t

-->> queue.h,67行目で ”DISPATCH_DECL(dispatch_queue);” と宣言されており、

-->> object.h, 50行目で ”#define DISPATCH_DECL(name) OS_OBJECT_DECL_SUBCLASS(name, dispatch_object)” と宣言されている。

 

dispatch_queue_t は dispatch_object_t のサブクラスということなので、型を指定してやるだけで dispatch_release() で解放可能と解釈できる。つまり、

	dispatch_queue_t	queue = dispatch_queue_create(@"com.bar.foo", NULL);
	…
	dispatch_release((dispatch_object_t)queue);

が正解、ということになる。

 

・・・が。ここでややこしいことになるのが、ARCだ。もう一度、 dispatch_object_t の定義があるファイルを見てみよう。定義があるすぐ上に、こんなコメントが記されている。

/*
* By default, dispatch objects are declared as Objective-C types when building
* with an Objective-C compiler. This allows them to participate in ARC, in RR
* management by the Blocks runtime and in leaks checking by the static
* analyzer, and enables them to be added to Cocoa collections.
* See <os/object.h> for details.
*/

----- usr/include/dispatch/object.h, line 42-

つまり、 dispatch_object_t や、そのサブクラスの dispatch_queue_t などは、Objective-C のクラスインスタンスと等価だと書いてある。そのため、ARCによるメモリマネジメントの対象になり、またコレクションクラスへの登録も可能である、云々。

要約すると、「dispatch_release() なんざ使ってるんじゃえよオラ」と。それどころか、コレクション登録も可能と言うことは、

	NSDictionary	*dic = [NSDictionary dictionaryWithObjectsAndKeys:
							dispatch_queue_create("com.bar.foo", NULL), @"queue1",
							dispatch_queue_create("com.bar.foo", NULL), @"queue2",
							nil];

なんて事もできちゃうわけだ。

 

というわけで、結論。

GCD関連のオブジェクトは、Objective-Cid と同等の扱いでOK。かつ、ARCで自動リリースされるので、明示的に解放してやる必要はない。

となりました。

« 2019 年 2月 »
2月
12
3456789
10111213141516
17181920212223
2425262728