none
マルチスレッドでビジー状態? RRS feed

  • 質問

  •  

    こんにちは、プログラム中困ったことがあったので、質問させていただきました。

    開発環境は「Visual Studio 2005」で、プロジェクトはC#の「windous アプリケーション」です。

     

    スレッドを初めて使ってみたのですが、動作が不安定で困っています。

    ソースコードは

     

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Text;
    using System.Windows.Forms;
    using System.Threading;

    namespace フォーム実験用
    {
        public partial class Form1 : Form
        {
            static int a;
            public Form1()
            {
                InitializeComponent();
            }

            public void label_chage(char s)
            {
                label1.Text = s.ToString();
            }

            private void Form1_Load(object sender, EventArgs e)
            {
                myClass mycl = new myClass();

                Thread newThread = new Thread(mycl.run);
                newThread.Start(this);

            }
        }

        class myClass
        {
            public void run(object form1)
            {
                Form1 form1_neo = (Form1)form1;

                char s = 'z';

                form1_neo.label_chage(s);
            }
        }
    }

     

    こんか感じです。

    どういう風になるかというと、実行するとフリーズしてそのうち「ビジー状態です」と、windousに警告されます。

    なぜかrunメソッドの中をコメントアウトすると問題なく動くのですが、コメントアウトしてるrunメソッドの中にブレークポイントを置くと止まります。

     

    ご指導のほどをよろしくお願いします。

     

    @自分はまだプログラムを始めたばかりの学生ですので、少し初心者向けの解説にしていただけるとたすかります。

    2008年12月9日 5:10

回答

  • 他のスレッドからGUIスレッドにあるコントロール(ここではlabel1)を操作することはできません。delegateを定義してdelegate経由で行わなくてはなりませんが、.NET Framework 2.0からはBackgroundWorkerが追加されましたので、これを持ちいると簡単に行えますので調べてみて下さい。

    2008年12月9日 5:51
    モデレータ

すべての返信

  • 他のスレッドからGUIスレッドにあるコントロール(ここではlabel1)を操作することはできません。delegateを定義してdelegate経由で行わなくてはなりませんが、.NET Framework 2.0からはBackgroundWorkerが追加されましたので、これを持ちいると簡単に行えますので調べてみて下さい。

    2008年12月9日 5:51
    モデレータ
  • 返信ありがとうございます。

     

    たしかにlabel1の操作を外すと、ちゃんとうごきました。

    ありがとうございました。
    2008年12月9日 7:20
  • 第1原則として、Windows Formsのコントロールオブジェクトは、そのコントロールが「最初に作成された」GUIスレッド以外で操作できないルールがあります。このルールに違反すると仰られているような現象にぶつかったりします。

    従って、別スレッドで行う処理の中で行える処理(計算)は、コントロールの情報を更新しない(参照は許されるときもあるけどお勧めしません)純粋な計算や処理に限られます。とはいえ別スレッドからコントロールを叩けないと不便ですので、別スレッドからコントロールを叩く(ことをGUIスレッドに依頼する)ための仕組み(Invoke)が存在します。C#ではこんな感じで利用します。

    Code Snippet

    class myClass

    {
      public void run(object form1)
      {
        Form1 form1_neo = (Form1)form1;

        char s = 'z';
        // Invoke呼び出し

        form1_neo.Invoke(new MethodInvoker(delegate()
          {
            form1_neo.label_chage(s);
          }));
        }
      }
    }

     

     

    個々の関数やクラスの意味はヘルプなどを参照してみてください。後、多分他の書き方もありますが、個人的にはこのパターンしか使って無いので説明は他の方にお任せします(^^;

    2008年12月9日 7:25
  • >>Mazさん

    お返事ありがとうございます。

     

    GUIスレッドに依頼するっていう形なんですね。勉強になりました、ありがとうございます。

    2008年12月9日 9:52