6

このコードでbutton1は、 を 2 回クリックすると、2 つの個別のスレッドが作成されます。ワンクリックで、ヒープ上に新しいスレッドを作成し、フィールドがヒープ上のt1新しいスレッドを指します。をクリックするbutton2と、最後のスレッド (をt1参照) が中止されます。

他のスレッド を中止するにはどうすればよいですか?

Thread t1;
ThreadStart ts1;

private void button1_Click(object sender, EventArgs e)
{
    ts1 = new ThreadStart(myfunc);
    t1 = new Thread(ts1);
    t1.Start();
}

private void button2_Click(object sender, EventArgs e)
{
    t1.Abort();
}
4

4 に答える 4

7

オブジェクト指向の答えは、スレッドのリストをフィールドとして保持することです。

private readonly List<Thread> threads = new List<Thread>();

そして、新しく構築されたスレッドを最初のハンドラーのリストに追加します。

var thread = new Thread(myfunc);
thread.Start();
threads.Add(thread);

次に、2 番目のハンドラーで各スレッドを反復処理し、それぞれを順番に中止します。

foreach(var thread in threads)
   thread.Abort();

しかし、ここで最も重要な点は、電話をかける正当な理由はほとんどないThread.Abortということです。

MSDN ページから:

スレッドがそれ自体で Abort を呼び出すと、結果は例外をスローするのと似ています。ThreadAbortException はすぐに発生し、結果は予測可能です。ただし、あるスレッドが別のスレッドで Abort を呼び出すと、実行中のコードが中断されます。静的コンストラクターが中止される可能性もあります。 まれに、これにより、そのアプリケーション ドメインでそのクラスのインスタンスが作成されなくなる場合があります。.NET Framework バージョン 1.0 および 1.1 では、finally ブロックの実行中にスレッドが中止される可能性があり、その場合、finally ブロックは中止されます。

中止されるスレッドがコードの保護された領域 (catch ブロック、finally ブロック、または制約付き実行領域など) にある場合、Abort を呼び出すスレッドはブロックされる可能性があります。Abort を呼び出すスレッドが、中止されたスレッドが必要とするロックを保持している場合、デッドロックが発生する可能性があります。

ManualResetEvent各スレッドが周期的な間隔でポーリングするように設定するなど、何らかの形式のシグナリングを使用する方がはるかに優れています。BackgroundWorkerまたは、タスクのキャンセルをサポートするクラスを使用することもできます(それを呼び出しCancelAsyncて、ワーカー スレッドをCancellationPending定期的にテストします)。.NET 4.0 を使用している場合は、TPLも使用できます。

于 2010-11-15T10:29:00.973 に答える
1

他の人は答えの長いバージョンを与えました、しかし明白な簡単な解決策は単にスレッドオブジェクトの再作成をスキップすることです:

public partial class Form1 : Form
{
    Thread thread1;
    ThreadStart threadStart1;

    public Form1()
    {
        InitializeComponent();

        threadStart1 = new ThreadStart(threadTarget);
        thread1 = new Thread(threadStart1);
        thread1.Name = "Button1 thread";    
    }

    private void button1_Click(object sender, EventArgs e)
    {
        thread1.Start();
    }

    private void button2_Click(object sender, EventArgs e)
    {
        thread1.Abort();
    }

    private void threadTarget()
    {
        Console.WriteLine(Thread.CurrentThread.Name);
        for (int i = 0; i < 100; i++)
        {
            Console.WriteLine(i);
            Thread.Sleep(500);
        }

    }
}

ただし、特にIOまたはデータベースを実行している場合は、この方法を使用するのではなく、これらのガイドの1つを使用して.NETのスレッド化について読むことを検討します(中止に関するJoseph Albahariのガイド-一言で言えばC#の作成者)。オブジェクトを予期しない状態のままにする可能性のある操作。

于 2010-11-15T11:24:06.163 に答える
1

ManualResetEventやWaitHandleなどの組み込みの同期プリミティブを確認することをお勧めします。Thread.Joinを使用してスレッドを結合しようとすると、スレッドが実行されているかどうかを確認できます。スレッドの中止は、スレッドが応答しない場合の最後の手段としてのみ実行する必要があります。

これは、スレッドが適切に停止される前にスレッドが再起動されないようにする方法を示すコードの変更された例です。

public partial class MainForm : Form
{
    private Thread t1;
    private ThreadStart ts1;
    private ManualResetEvent t1resetEvent;

    public MainForm()
    {
        InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
        // Got a thread?
        if (t1 != null) {                
            if (!t1.Join(0)) {
                // The thread seems to be running.
                // You have to stop the thread first.
                return;
            }
        }

        t1resetEvent = new ManualResetEvent(false);
        ts1 = new ThreadStart(MyFunc);
        t1 = new Thread(ts1);
        t1.Start();
    }

    private void button2_Click(object sender, EventArgs e)
    {
        // Got a thread?
        if (t1 != null)
        {
            // Set the reset event so the thread
            // knows it's time to stop.
            t1resetEvent.Set();

            // Give the thread four seconds to stop.
            if (!t1.Join(4000)) {
                // It did not stop, so abort it. 
                t1.Abort();
            }
        }
    }

    private void MyFunc()
    {
        // Long running operation...
        while (true)
        {
            // Do someone want us to exit?
            if (t1resetEvent.WaitOne(0)) {
                return;
            }                
        }
    }
}
于 2010-11-15T11:08:07.927 に答える
0

また、スレッドで Abort を呼び出すことは悪であることにも注意してください。ブール条件などでスレッドを停止する必要があります。

これをチェックして:

http://www.interact-sw.co.uk/iangblog/2004/11/12/cancellation

于 2010-11-15T10:35:43.013 に答える