none
スレッドセーフのプログラミングについて RRS feed

  • 質問

  •     Public Sub LogWrite(ByRef Ldat As String)

            Dim MyStr As String

            MyStr = VB6.Format(Today, "Long Date")

            Dim FileName As String = My.Application.Info.DirectoryPath & "\log" & VB6.Format(MyStr, "yyyy-mm-dd") & ".log"
            Dim Writer As IO.StreamWriter
            Dim Encode As System.Text.Encoding
            '文字コードにShiftJISを指定。(UTF8の場合は指定不要)
            Encode = System.Text.Encoding.GetEncoding("Shift-JIS")

            '既に存在するテキストに追加する場合は第2引数をTrueにする。
            Writer = New IO.StreamWriter(FileName, True, Encode)
            Writer.WriteLine(Now & " :: " & Ldat)
            Writer.Close()


        End Sub

    こんな関数を作成しまして、マルチスレッドからログ出力させたいのですが、StreamWriterはスレットセーフでないとのこと。ヘルプを見て、実装しようと思ったのですが、ラッパー方法がわかりません。この関数をどう直せばスレッドセーフになるのでしょうか?

     

    2007年6月5日 9:09

回答

  • 問題はStreamWriterがスレッドセーフでないこととは別のところにあるわけですが、
    そこのところは認識できるでしょうか?

    ※このコードに限って言えば、StreamWriterがスレッドセーフでないことはある意味問題なしなのです。

     

    2007年6月5日 10:34
  • 外池と申します。

     

    私もマルチスレッドのプログラミングの経験はあまりないので、偉そうなことは言えないのですが、多少の経験から気になることを申し上げれば、

     

    一つのファイルに対して、複数のスレッドからStreamと関連付ける要求がなされ、さらにそれぞれのStreamから書き込みがなされるわけですが、その点は大丈夫でしょうか? この場合、スレッドごとにStreamのインスタンスが作成されるような書き方になっているので、Stream自体にマルチスレッドの問題が出るとは、あまり思えません。

     

    スレッド・セーフ云々の話は、一つのインスタンスが複数のスレッドからアクセスを受ける場合に問題になるわけで、この場合、Streamよりも、さらにその下流のファイルそのものが大丈夫か? と気になります。

     

    あるスレッドが、"10:34:23 Event HOGEHOGE raised" と書き込もうとし、他のスレッドがほぼ同時刻に"10:34:23 The othere event HUMHUM raised"と書き込もうとし・・・、ファイル上にはこれらの文が、キチっとわかれて書き込まれる保証はないですよね・・・。HOGEHOGEとHUMHUMがゴッチャになって書き込まれるかもしれません。

     

    私の経験では、書き込みは一つのスレッドでなされ、同じファイルを同時に、複数のスレッド(どころか、他の複数のプロセス)で読み出すことは、まったく問題なくできました。書き込みは、どうでしょう? Streamのインスタンスをあるファイルと関連づけながら作るとき、排他的な制御をどうするか、のオプションを指定できるコンストラクタがありますので、チェックしてみてください。

     

     

     

     

    2007年6月6日 6:33
  • とりあえず、単一のWindowsアプリケーション内でのマルチスレッドに対応するため程度であれば、クラスに変数をひとつ定義して、SyncLockで排他してやればいいです。

    ※ログ出力用のクラスをどのように扱っているかにもよりますが。

     

    使う側がスレッドを意識するのはしんどいですし、それ以上に使い方を間違えるとまずいので、ログ出力のメソッド側で対応してやるのが望ましいです。

    細かい話はもういやになるくらいいろいろとありますが、とりあえずはそんな程度でしょう。

     

    まあ、それくらいの簡単なログ出力機能ならTraceとか使ったほうがいいとも思いますが。

     

    2007年6月7日 14:32

すべての返信

  • 問題はStreamWriterがスレッドセーフでないこととは別のところにあるわけですが、
    そこのところは認識できるでしょうか?

    ※このコードに限って言えば、StreamWriterがスレッドセーフでないことはある意味問題なしなのです。

     

    2007年6月5日 10:34
  • すいません、まったく認識できておりません。

    VB6で作成したものをVB2005で自動コンバートして、その後でBackGroundWorkerを実装してから動作確認をしておりました。

    どこがまずいのか、ご指摘いただけないでしょうか。

     

     

    2007年6月6日 5:12
  • 外池と申します。

     

    私もマルチスレッドのプログラミングの経験はあまりないので、偉そうなことは言えないのですが、多少の経験から気になることを申し上げれば、

     

    一つのファイルに対して、複数のスレッドからStreamと関連付ける要求がなされ、さらにそれぞれのStreamから書き込みがなされるわけですが、その点は大丈夫でしょうか? この場合、スレッドごとにStreamのインスタンスが作成されるような書き方になっているので、Stream自体にマルチスレッドの問題が出るとは、あまり思えません。

     

    スレッド・セーフ云々の話は、一つのインスタンスが複数のスレッドからアクセスを受ける場合に問題になるわけで、この場合、Streamよりも、さらにその下流のファイルそのものが大丈夫か? と気になります。

     

    あるスレッドが、"10:34:23 Event HOGEHOGE raised" と書き込もうとし、他のスレッドがほぼ同時刻に"10:34:23 The othere event HUMHUM raised"と書き込もうとし・・・、ファイル上にはこれらの文が、キチっとわかれて書き込まれる保証はないですよね・・・。HOGEHOGEとHUMHUMがゴッチャになって書き込まれるかもしれません。

     

    私の経験では、書き込みは一つのスレッドでなされ、同じファイルを同時に、複数のスレッド(どころか、他の複数のプロセス)で読み出すことは、まったく問題なくできました。書き込みは、どうでしょう? Streamのインスタンスをあるファイルと関連づけながら作るとき、排他的な制御をどうするか、のオプションを指定できるコンストラクタがありますので、チェックしてみてください。

     

     

     

     

    2007年6月6日 6:33
  • 情報ありがとうございます。

    そうですね、排他制御を忘れておりました。

    BackgroundWorkerのProgressChangedに引渡して、ログに書き込むようにしてみます。

     

    2007年6月7日 1:14
  • とりあえず、単一のWindowsアプリケーション内でのマルチスレッドに対応するため程度であれば、クラスに変数をひとつ定義して、SyncLockで排他してやればいいです。

    ※ログ出力用のクラスをどのように扱っているかにもよりますが。

     

    使う側がスレッドを意識するのはしんどいですし、それ以上に使い方を間違えるとまずいので、ログ出力のメソッド側で対応してやるのが望ましいです。

    細かい話はもういやになるくらいいろいろとありますが、とりあえずはそんな程度でしょう。

     

    まあ、それくらいの簡単なログ出力機能ならTraceとか使ったほうがいいとも思いますが。

     

    2007年6月7日 14:32
  • なちゃさん、外池さん

     

     情報ありがとうございました。メインでログ出力をさせるようにして、ReportProgressで-1,"メッセージ"をスレッドから送るようにしました。

    ProgressPercentageは、作業カウントを送ってましたので、ログ出力判定フラグのつもりで-1をセットしてみました。動作は問題ないようです。

     

    今後ともよろしくお願いいたします。

    2007年6月8日 5:02