- - PR -
File.Exists を別スレッド化する。
投稿者 | 投稿内容 | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
投稿日時: 2008-05-22 12:01
お世話になっています。
記事で非同期デリゲートを勉強し、コードを書いてみたのですが、別スレッドの結果をうまく処理できません。 きちんと理解できなくて、申し訳ありませんが教えていただけるとありがたいです。 Class Class1 '非同期で呼び出すメソッドと同じシグネチャのデリゲート Delegate Function FileExistsAsyncDelegate( _ ByVal FileName As String) As Boolean 'エントリポイント Public Shared Function FileExistTimeOut( _ ByVal FileName As String, ByVal TimeOut As Integer) As Boolean 'デリゲートオブジェクトの作成 Dim dlgt As New FileExistsAsyncDelegate(AddressOf FileExists) '非同期呼び出しを開始 Dim ar As IAsyncResult = dlgt.BeginInvoke(FileName, _ New AsyncCallback(AddressOf CallbackMethod), dlgt) System.Threading.Thread.Sleep(TimeOut) Return False End Function '非同期で呼び出すメソッド Private Shared Function FileExists(ByVal FileName As String) As Boolean Return File.Exists(FileName) End Function 'コールバックメソッド Private Shared Sub CallbackMethod(ByVal ar As IAsyncResult) 'デリゲートオブジェクトの取得 Dim dlgt As FileExistsAsyncDelegate = _ CType(ar.AsyncState, FileExistsAsyncDelegate) 'EndInvokeを呼び出し、結果を取得 Dim ret As Boolean = dlgt.EndInvoke(ar) End Sub End Class | ||||||||||||
|
投稿日時: 2008-05-22 12:25
EndInvokeの戻り値を普通にFileExistsの戻り値としてみればよいだけなので ここまでできていて何が「うまく処理」できないのかわかりません。 このコードは抜粋ですか? 抜粋でないなら、あとはただretを返せばいいだけだと思います。 動作確認はしていませんが。 それと、無理にCallBackを使うことはありません。 忘れてはいけない後処理、例えばリソースの解放などがない限り、 後処理はメインスレッドでも出来ます。 今回はFile.ExistsですからCallbackを使わないほうが 短くて簡単にできると思います。 | ||||||||||||
|
投稿日時: 2008-05-22 13:27
れいさん、ありがとうございます。
御指導のとおり、CALLBACKをやめて、EndInvokeの戻り値を取得したのですが、アプリケーションがフリーズしてしまいました。 '非同期で呼び出すメソッドと同じシグネチャのデリゲート Delegate Function FileExistsAsyncDelegate( _ ByVal FileName As String) As Boolean Public Shared Function FileExistTimeOut( _ ByVal FileName As String, ByVal TimeOut As Integer) As Boolean 'デリゲートオブジェクトの作成 Dim dlgt As New FileExistsAsyncDelegate(AddressOf FileExists) '非同期呼び出しを開始 Dim ar As IAsyncResult = dlgt.BeginInvoke(FileName, Nothing, Nothing) 'タイムアウト System.Threading.Thread.Sleep(TimeOut) 'EndInvokeを呼び出し、結果を取得 Dim ret As Boolean = dlgt.EndInvoke(ar) Return ret End Function '非同期で呼び出すメソッド Private Shared Function FileExists(ByVal FileName As String) As Boolean Return File.Exists(FileName) End Function | ||||||||||||
|
投稿日時: 2008-05-22 13:37
EndInvokeは非同期操作が終わるまで待機しますからフリーズしますよ。 それにこれじゃタイムアウトじゃなくてただの待ちです。 ar.AsyncWaitHandle.WaitOne を使いましょう。 | ||||||||||||
|
投稿日時: 2008-05-22 14:17
れいさん、タイムアウトのところをar.AsyncWaitHandle.WaitOneにしたらできました!!
WaitOneの引数のBooleanなのですが、「待機する前に同期ドメインを終了するかどうか」というのがよく分かりません。 とりあえずFalseにしました。 すみませんがもう少し教えていただきますようおねがいします。 'タイムアウト Dim ret As Boolean If ar.AsyncWaitHandle.WaitOne(TimeOut, False) Then 'EndInvokeを呼び出し、結果を取得 ret = dlgt.EndInvoke(ar) Else ret = False End If Return ret | ||||||||||||
|
投稿日時: 2008-05-22 16:05
あー。 いまさらですが、やっとやりたいことが理解できました。 タイムアウト付のExistsメソッドを作りたいのですね? それならば、EndInvokeを必ず呼ぶように作らないと、 リソースが解放されません。 (気にしないという手もありますが…、私は気にします) ですので、そのコードではダメです。 いろいろ対処する手はありますが、私がよく使うのは次の2つです。 1. キャンセルされたIAsyncResultリストを保持しておいて、 定期的に「終わったか」を調べてEndInvokeを呼んで廃棄する 2. コールバックでEndInvokeを呼ぶ 1の方は同期を考えなくていいので楽で、コードもわかりやすく短いのですが、 モジュール化が困難です。 2の方は局所的なコードになり再利用もしやすいのですが、 同期処理がぐちゃぐちゃです。 という感じで、最初に言ったように私にはいい方法が思いつきません。 IAsyncResultのパターンは非常に応用性が高いのですが、 私には「タイムアウト」や「キャンセル」がうまく作れません。 どのコードも「ぐちゃぐちゃ」です。 いま適当に作った2の方法のコードを挙げておきますが、 上記のようにぐちゃぐちゃです。 誰かいい方法があったら教えてください。 (ちなみにWindows.Formsでは1の方法を普段使っています)
何回も言いますが、非常に醜いコードです。 なるべく参考にしないことをオススメします。
SynchronizationAttributeが関与してるときに意味を持ちます。 falseにしておけば再利用しやすくなりますので、とりあえずfalseで。 詳しくはMSDNのWaitHandle周りのドキュメントを読みましょう。 | ||||||||||||
|
投稿日時: 2008-05-22 16:50
れいさん、そのとおりです。
タイムアウト付きのExistsメソッドを作りたかったのです。 このコードではだめなのですね。 私には、ハードルが高いですが、れいさんのコードをじっくりと噛締めたいと思います。 | ||||||||||||
|
投稿日時: 2008-05-23 09:17
やっていてふと思ったのですが、タイムアウト付きのExistsメソッドを使っても、タイムアウトするまでアプリケーションがフリーズしてしまいます。
Exists自体を別スレッドに任せた方がよいのでしょうか? 普通はどのように設計するものなのでしょう。 スタンダードな手法等があれば、御教授よろしくおねがいします。 |