2016-06-02 9 views
5

ゴー1.7ベータ1は、ここでは、今朝リリースさthe release notes draft of Go 1.7ですました。新しい機能KeepAliveがパッケージruntimeに追加されました。 The doc of runtime.KeepAlive例を与えている:ファイルディスクリプタ Dを含有する構造体の場合、P点、例えばGoでは、いつ変数に到達できなくなるのですか?

、pはファイナライザを有する:

type File struct { d int } 
d, err := syscall.Open("/file/path", syscall.O_RDONLY, 0) 
// ... do something if err != nil ... 
p := &FILE{d} 
runtime.SetFinalizer(p, func(p *File) { syscall.Close(p.d) }) 
var buf [10]byte 
n, err := syscall.Read(p.d, buf[:]) 
// Ensure p is not finalized until Read returns. 
runtime.KeepAlive(p) 
// No more uses of p after this point. 

The doc of runtime.SetFinalizerruntime.KeepAliveについて説明を与えていますそれは、そのファイルディスクリプタを閉じ、関数内のpの 最後の使用はsyscall.Write(PD、bufが、 サイズ)への呼び出しがある場合はすぐにプログラムとしては syscall.Writeに入ると、そしてpは到達できないことがあります。ファイナライザは は、それが閉じられたファイル 記述子への書き込みをされているためsyscall.Writeが失敗し、p.dを閉じて、その時点で実行することができる(または、より悪い、完全に異なるファイルディスクリプタに異なるゴルーチンで をオープンしました)。この問題を回避するには、syscall.Writeを呼び出した後に runtime.KeepAlive(p)を呼び出します。

私は変数pがまだ生命の範囲を去っていないということを私に混乱させました。なぜそれが到達不能になるのですか?これは、変数がそのライフスコープにあるかどうかに関わらず、次のコードでその変数を使用しないと変数に到達できないことを意味しますか?

答えて

7

コードがその変数が再び参照されるポイントに到達できないことをランタイムが検出すると、変数が到達不能になります。あなたが投稿例で

syscall.Open()は、ファイルを開くために使用されます。 (ただ int値である)返されたファイルディスクリプタは structに「ラップ」されます。その後、ファイル記述子を閉じるこの構造体の値にファイナライザが付加されます。この構造体の値が到達不能になると、ファイナライザはいつでも実行され、ファイルディスクリプタのクローズ/無効化/再使用は、システムコール Read()の実行中に予期しない動作やエラーを引き起こす可能性があります。 syscall.Read()が呼び出される(とファイルディスクリプタ p.dがそれに渡された)とき

ゴーコードでこの構造体の値pの最後の使用です。 syscallの実装では、の開始syscall.Read()の後にそのファイル記述子を使用しますが、syscall.Read()が返されるまでそれを行うことがあります。しかし、このファイル記述子の使用は、Goコードとは独立しています。

ので、構造体の値pは、システムコールの実行中に使用され、システムコールのブロック移動コードはそれが戻るまでされていません。 pのみRead()を呼び出すための引数を提供するために使用されているため、囲碁ランタイムがRead()Read()前リターン)の実行中に到達不能としてpをマークすることができ、またはされた意味の実際の実行は、(を開始する前であっても。

したがって runtime.KeepAlive()への呼び出し:この呼び出しは syscall.Read()、それ 参照変数 pあるので、これは Read()呼び出しの後であるため、ゴーランタイムは、到達不能 p Read()前にリターンをマークすることはできません。

pを有効にする」ために他の構造を使用できます。 _ = pまたはそれを返す。 runtime.KeepAlive()がバックグラウンドで魔法のような何もしない、その実装は次のようになりますので

func KeepAlive(interface{}) {} 

runtime.KeepAlive()

がはるかに優れた代替手段を提供しません:私たちは生きている( Finalizersのランを防ぐために) p維持したい明確

  • それを文書。
  • _ = pのような他の構成要素を使用すると、将来のコンパイラによって「最適化」される可能性がありますが、runtime.KeepAlive()では呼び出されません。
関連する問題