none
静的(static)変数とマルチスレッド RRS feed

  • 質問

  • スレッド毎の静的(static)変数って持つ事は可能でしょうか?

     

    前置きの説明が少し長くなりますが、

    TextBoxとButtonがあるFormがあるとして、各TextBoxにはValidatingイベントハンドラが

    登録されています。

    そのハンドラでは、何も入力されていなければ、エラーを表示します(ErrorProviderにて)。

    但し、CancelEventArgs.Cancel=trueはしない。フォーカス移動は可能にする為に。

    但し(その2)、Buttonクリックで、Form.ValidateChildren()をコールするので、その際は

    CancelEventArgs.Cancelにtrueをセットする。

     

    その為に、次のソースの様にstatic変数を1つ設けています。(実際は共通ライブラリ化

    しているので、static変数の宣言位置はForm外になります。)

     

    public static bool cancelflag = false;
    private void textBox1_Validating(object sender, CancelEventArgs e)
    {
        bool cancel = (textBox1.Text == "");
        errorProvider1.SetError(textBox1, "");
        if (cancel)
        {
            e.Cancel = cancelflag;
            errorProvider1.SetError(textBox1, "入力しろ");
        }
    }
    private void button1_Click(object sender, EventArgs e)
    {
        cancelflag = true;
        bool validate = this.ValidateChildren();
        cancelflag = false;
        if (!validate)
        {
            return;
        }
        MessageBox.Show("完了");
    }

     

    static変数はシングルスレッド時は何の問題もないですが、マルチスレッド時(実際には

    マルチスレッド化するかどうかは決まってませんが)、static変数は、各スレッドから

    参照(設定)される為、意図しない動作になりえるかと思うのですが。

     

    前置きが長くなりましたが、質問内容は、スレッド毎に管理できるstatic変数って

    ないものでしょうか?

     

    ご教授の程、宜しくお願い致します。

     

    環境:
    Windows Vista Ultimate
    Visual Studio 2005 Professional Edition SP1
    .NET Framework 2.0

     

    追伸:

    今回、例に挙げたソース(方式)については、一考の余地があるので、この方式の別手段に

    ついてもご指摘は賜りますが、質問内容は件名の通り「静的(static)変数とマルチスレッド」

    をメインに宜しくお願い致します。

     

    2008年4月18日 2:44

回答

  • スレッドごとの静的変数って、少し矛盾している気もしますが、例えば、

    Dictionary<Thread, bool>

    は、スレッドごとの bool 値を保持できます。

    今回の場合、スレッドというよりはフォームインスタンスごとの

    Dictionary<Form, bool>
    でも、事足りるのではないでしょうか。

     

    別案ですが、Form.AutoValidate に AutoValidate.EnableAllowFocusChange をセットしておくと、Cancel を true にしてもフォーカスの移動は可能になります(ValidateChildren は false を返します)。

    2008年4月18日 8:29
  •  @ぶるーの さんからの引用

    スレッド毎の静的(static)変数って持つ事は可能でしょうか?

     
    単純な値なら ThreadStaticAttribute 属性を付与すればよいです。
     
    単純な値ではない場合、ThreadStaticAttribute 属性では初期化や後処理に問題が発生する場合があります。そのような場合には LocalDataStore を利用して自身で値の管理をすることができます。
     
    Thread クラスの AllocateNamedDataSlot(), AllocateDataSlot(), GetData(), SetData() などを利用します。ドキュメントだと、
     
    スレッド ローカル ストレージおよびスレッドごとの相対静的フィールド
     
    あたりですかね。
     

     @ぶるーの さんからの引用

    今回、例に挙げたソース(方式)については、一考の余地があるので、この方式の別手段についても

     
    何をどう共有ライブラリ化しているのかがイマイチはっきりしませんが、この手順の場合にフラグが必要とするコンテキストは、スレッドではなくフォームですよね。ですので、TLS を利用する必要はまったくないのではないか?と思います。
     
    Code Snippet
     
    public static void InstallValidationEvent(Form targetDialog)
    {
      foreach (TextBox textBox in GetTargetTextBoxes(targetDialog)
        InstallValidationEvent(textBox);
     
      InstallValidationEvent(targetDialog.AcceptButton);
    }

     

     

    みたいなメソッドを提供しているライブラリと想定して、
     
    Code Snippet
     
    private static Dictionary<Form, bool> closingFlags;
     
    public static void InstallValidationEvent(Form targetDialog)
    {
      foreach (TextBox textBox in GetTargetTextBoxes(targetDialog)
        InstallValidationEvent(textBox);
     
      InstallValidationEvent(targetDialog.AcceptButton);
     
      closingFlags[targetDialog] = false;
      targetDialog.Disposed += Cleanup;;
    }
     
    private static void Cleanup(object sender, EventArgs e)
    {
      closingFlags.Remove(sender);
    }

     

     
    みたいなかんじでよさげです。根本的には、Validation 関連の手順やイベントを少し見直すべきかな?
    2008年4月19日 2:30

すべての返信

  • スレッドごとの静的変数って、少し矛盾している気もしますが、例えば、

    Dictionary<Thread, bool>

    は、スレッドごとの bool 値を保持できます。

    今回の場合、スレッドというよりはフォームインスタンスごとの

    Dictionary<Form, bool>
    でも、事足りるのではないでしょうか。

     

    別案ですが、Form.AutoValidate に AutoValidate.EnableAllowFocusChange をセットしておくと、Cancel を true にしてもフォーカスの移動は可能になります(ValidateChildren は false を返します)。

    2008年4月18日 8:29
  •  @ぶるーの さんからの引用

    スレッド毎の静的(static)変数って持つ事は可能でしょうか?

     
    単純な値なら ThreadStaticAttribute 属性を付与すればよいです。
     
    単純な値ではない場合、ThreadStaticAttribute 属性では初期化や後処理に問題が発生する場合があります。そのような場合には LocalDataStore を利用して自身で値の管理をすることができます。
     
    Thread クラスの AllocateNamedDataSlot(), AllocateDataSlot(), GetData(), SetData() などを利用します。ドキュメントだと、
     
    スレッド ローカル ストレージおよびスレッドごとの相対静的フィールド
     
    あたりですかね。
     

     @ぶるーの さんからの引用

    今回、例に挙げたソース(方式)については、一考の余地があるので、この方式の別手段についても

     
    何をどう共有ライブラリ化しているのかがイマイチはっきりしませんが、この手順の場合にフラグが必要とするコンテキストは、スレッドではなくフォームですよね。ですので、TLS を利用する必要はまったくないのではないか?と思います。
     
    Code Snippet
     
    public static void InstallValidationEvent(Form targetDialog)
    {
      foreach (TextBox textBox in GetTargetTextBoxes(targetDialog)
        InstallValidationEvent(textBox);
     
      InstallValidationEvent(targetDialog.AcceptButton);
    }

     

     

    みたいなメソッドを提供しているライブラリと想定して、
     
    Code Snippet
     
    private static Dictionary<Form, bool> closingFlags;
     
    public static void InstallValidationEvent(Form targetDialog)
    {
      foreach (TextBox textBox in GetTargetTextBoxes(targetDialog)
        InstallValidationEvent(textBox);
     
      InstallValidationEvent(targetDialog.AcceptButton);
     
      closingFlags[targetDialog] = false;
      targetDialog.Disposed += Cleanup;;
    }
     
    private static void Cleanup(object sender, EventArgs e)
    {
      closingFlags.Remove(sender);
    }

     

     
    みたいなかんじでよさげです。根本的には、Validation 関連の手順やイベントを少し見直すべきかな?
    2008年4月19日 2:30
  • TH01さん、囚人さん、K.Takaokaさん、回答ありがとうございます。

     

    ThreadStaticAttribute属性で対応できるかどうか検討してみます。

     

    >別案ですが、Form.AutoValidate に AutoValidate.EnableAllowFocusChange をセット

    ありがとうございます。

    こういうプロパティがあったのですね。

    この方式、使わせて頂きます。

     

    ありがとうございました。

     

    2008年4月21日 8:18