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();
    }
}

当我单击一次按钮时,一切正常。但是当我再次按下按钮时,什么也没有发生。

当我不使用 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);           
        }
    }
}

这是一个小的网络爬虫程序的一小部分。它导航到需要一些登录信息的网页。当我到达我真正想要的页面时,他应该在新的 Internet Explorer 中打开它。

当我调用此代码并关闭表单时,它仍然在进程树中可见。而且当我多次单击该按钮时,使用的内存不断增加,我怀疑这是某种内存泄漏。

4

2 回答 2

2

首先,永远不要使用Thread.Abort(), 。请参阅此 thread.abort() 正常且安全吗?有关原因的更多详细信息。

网上很多 关于使用. _ _ 除非真的需要,否则我建议避免使用它,在这种情况下,我认为不需要。你最好只实现一个单次计时器,可能有半秒的超时,并在每次击键时重置它。这样,您的昂贵操作只会在用户不活动半秒或更长时间(或您选择的任何长度)后发生。 Thread.Abort()

Join()您可以使用Method代替使用 abort 。此方法阻塞调用线程,直到线程终止。

它使用的一个例子是

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 回答
1

您是否可以使用.net 4 +,如果可以的话,您可以使用 TPL,这将大大简化为

public class MyClass
    {
        public void Do_your_thing()
        {
            // for async execution
            Task.Factory.StartNew(Running_code);

            // for synchronous execution
            // CAUTION !! If invoked from UI thread this will freeze the GUI until Running_code is returned.
            //Task.Factory.StartNew(Running_code).Wait(); 
        }

        private void Running_code()
        {
           Thread.Sleep( 2000 );
           Debug.WriteLine( "Something was done" );
        }
    }

此外,如果 Running_Code 方法正在执行 IO 绑定的操作,则 TPL 可以利用 IO 完成端口,并且该操作可能完全是无线程的。

编辑:

看看这个 SO 线程。新线程中的 WebBrowser 控件

显然 webbrowser 控件不能很好地与非 UI 线程配合使用。

于 2013-04-22T09:41:10.153 回答