4

基本的に、ボタンを含むフォームがあります。ボタンを押すと、スレッドを実行するクラスのインスタンスが作成されます。スレッドが完了すると、Thread.Abort() が自動的に呼び出されます。

私が現在持っているコードはこれになります:

ボタン:

private void Buttonclick(object sender, EventArgs e)
{
     MyClass c = new MyClass()
     c.Do_your_thing();
}

クラス:

public class MyClass
{
    Thread t;

    public void Do_your_thing()
    {
         t = new Thread(Running_code);
         t.Start();
    }

    private void Running_code()
    {
         //Perform code here
         t.Abort();
    }
}

ボタンを 1 回クリックすると、すべてが機能します。しかし、もう一度ボタンを押しても何も起こりません。

t.Abort() を使用しないと、すべてが機能します。ただし、t.Abort() を使用しないと、メモリ リークが発生し、プログラムが適切に閉じられません (スレッドが閉じられないため、プロセスは存続します)。

誰が私に何が起こっているのか説明できますか? どうすれば修正できますか?

編集:リクエストに応じて、実際のコードを投稿しています

public class MyClass
{
    public void Test()
    {
        t = new Thread(() =>
            {
                wb.DocumentCompleted += get_part;
                wb.Navigate("http://www.google.com");
                Application.Run();
            });

        t.SetApartmentState(ApartmentState.STA);
        t.Start();
    }

    public void get_part(object sender, WebBrowserDocumentCompletedEventArgs e)
    {
        var br = sender as WebBrowser;
        string url = e.Url.ToString();

        //Here is some code that compares the url to surten predefined url. When there is a match, it should run some code and then go to a new url

        if(url == string_final_url)
        {
            //Finally at the url I want, open it in a new Internet Explorer Window
            Process proc = Process.Start("IExplore.exe", url);           
        }
    }
}

これは小さな webscraper プログラムの一部です。ログイン情報が必要な Web ページに移動します。私が実際に表示したいページにたどり着いたら、彼はそれを新しい Internet Explorer で開く必要があります。

このコードを呼び出してフォームを閉じると、プロセス ツリーに表示されたままになります。また、ボタンを複数回クリックすると、使用されるメモリが増え続けます。これは、何らかのメモリ リークであると思われます。

4

2 に答える 2

2

まず、決して使用しないでくださいThread.Abort()この thread.abort() は正常で安全ですか?を参照してください。理由の詳細については。

の使用に関する多くの警告 ネット上にあります。本当に必要でない限り、避けることをお勧めしますが、この場合はそうではないと思います。おそらく0.5秒のタイムアウトでワンショットタイマーを実装し、キーストロークごとにリセットする方がよいでしょう。このようにして、コストのかかる操作は、0.5 秒以上 (または任意の長さ) のユーザーの非アクティブ状態の後にのみ発生します。 Thread.Abort()

abort を使用する代わりに、Join()Methodを使用できます。このメソッドは、スレッドが終了するまで呼び出しスレッドをブロックします。

その使用例は、

Thread t1 = new Thread(() => 
{ 
    Thread.Sleep(4000);
    Console.WriteLine("t1 is ending.");
});
t1.Start();

Thread t2 = new Thread(() => 
{ 
    Thread.Sleep(1000);
    Console.WriteLine("t2 is ending.");
});
t2.Start();

t1.Join();
Console.WriteLine("t1.Join() returned.");

t2.Join();
Console.WriteLine("t2.Join() returned.");

これが役立つことを願っています。


編集します。あなたのコメントに対処するため。Join() の呼び出しは、スレッドの割り当てを解除するものです。他に何もする必要はありません。スレッドが終了する前に、スレッドが使用している可能性のあるすべてのリソースをクリーンアップすることを確認してください。

とはいえ、明示的にスレッドを管理するのではなく、スレッド プールまたはタスク並列ライブラリ (TPL) の使用を検討することをお勧めします。それらは使いやすく、この種のことをよりスムーズに処理します。

于 2013-04-22T09:26:47.507 に答える