2

Lock Up Unlockedの記事に従ってデッドロック状態の C# Windows Form Application に変更を実装した後も、以前の記事Locked Up! のコードと同じ問題が発生しています。

つまり、ボタンをすばやく数回クリックすると、アプリケーションがハングアップします (応答しなくなります)。

なんで?
そして、それを修正する方法は?

using System;
using System.Windows.Forms;
using System.Threading;

namespace LockupUnlocked
{
  public partial class Form1 : Form
  {
    public Form1()
    {
      InitializeComponent();
      _t = new Thread(new ParameterizedThreadStart(WorkerThread));
    }

    private Thread _t;
    private object lockObject = new object();

    private bool StopThread = false;  ////changes added to avoid deadlock

    private void WorkerThread(object sender)
    {
      Thread.Sleep(1000);
      //while (true)
      while (!StopThread)//changes added to avoid deadlock
      {
        string result = "This is a Test";
        IAsyncResult aResult;////changes added to avoid deadlock
        lock (lockObject)
        {
          Thread.Sleep(25);
          //lblResult.Invoke(new MethodInvoker(delegate { lblResult.Text = result; }));
          aResult = lblResult.BeginInvoke//changes to avoid deadlock
            (new MethodInvoker(delegate { lblResult.Text = result; }));
        }
        lblResult.EndInvoke(aResult);//changes added to avoid deadlock
        Thread.Sleep(500);
      }
    }
    private void Form1_FormClosing(object sender, FormClosingEventArgs e)
    {
      StopThread = true;
    }
    private void Form1_Load(object sender, EventArgs e)
    {
      _t.Start();
    }

    private void button1_Click(object sender, EventArgs e)
    {
      lock (lockObject)//changes added to avoid deadlock
      {
        lblResult.Text = "Override the Test";
      }
    }
  }
}
4

2 に答える 2

3

私には、必ずしもデッドロックではなく、ロックの競合のように見えます。

25 ミリ秒 (25 秒ではなく、25000 秒) ごとに while ループを繰り返します。ボタンをクリックすると、ロックの要求が中断されます。スリープがロック スコープ内にあるため、そのロックが与えられない可能性があります。

ボタンをクリックしなくても、これは機能しているように見えますが、ロックを待機しているボタンのクリックは UI スレッドをブロックし、フォームがそれ自体をペイントする時間がないため、「応答していません」というメッセージが表示されます。

実際には、テキスト値を更新するためにロックする必要はありません。から呼び出すとControl、メッセージが UI メッセージ キューにプッシュされ、UI スレッドで同期的に処理されます。最悪の事態は競合状態であり、共有状態が破損することはありません。

ロックを解除しても、コードは期待どおりに機能するはずです。


このサンプルで何を達成しようとしているのかわからないため、サンプル コードを提供することをためらっています。

于 2013-02-26T10:13:52.150 に答える
2

Windows.FormsでGUiアクセスを必要とする競合するスレッドを処理するためのパターンには、InvokeRequiredプロパティとInvoke関数が含まれます。その場合、ロックは必要ありません。

namespace WindowsFormsApplication1
{
  using System;
  using System.Threading;
  using System.Windows.Forms;

  public partial class Form1 : Form
  {
    private Thread thread;

    public Form1()
    {
      this.InitializeComponent();
      this.thread = new Thread(this.WorkerThread);
    }

    private void WorkerThread(object sender)
    {
      Thread.Sleep(1000);

      while (true)
      {
        Thread.Sleep(25);

        this.SetText("from thread");

        Thread.Sleep(500);
      }
    }

    private void Form1_FormClosing(object sender, FormClosingEventArgs e)
    {
      this.thread.Abort();
    }

    private void Form1_Load(object sender, EventArgs e)
    {
      this.thread.Start();
    }

    /// <summary>
    /// This is a callback for the SetText Method.
    /// </summary>
    /// <param name="text">The text.</param>
    private delegate void SetTextCallback(string text);

    /// <summary>
    /// This sets a text. 
    /// It's thread safe, you can call this function from any thread. 
    /// If it's not called from the UI-thread, it will invoke itself
    /// on the UI thread.
    /// </summary>
    /// <param name="text">The text.</param>
    private void SetText(string text)
    {
      if (this.InvokeRequired)
      {
        this.Invoke(new SetTextCallback(this.SetText), text);
      }
      else
      {
        this.lblResult.Text = text;  
      }
    }

    private void Button1_Click(object sender, EventArgs e)
    {
      this.SetText("from button");
    }
  }
}
于 2013-02-26T10:34:50.887 に答える