在C#中终止/加入一个线程

时间:2016-10-04 17:58:13

标签: c# multithreading

我似乎无法在C#中杀死我的线程。该程序似乎陷入了FormClosing事件的无限循环中。

编辑//我试图结束线程并在FormClosing事件被触发时关闭整个程序。

以下是代码:

public partial class Form1 : Form
{
    private Thread thread;
    private volatile bool threadRunning = true;

    public Form1()
    {
        InitializeComponent();
    }

    private void Loop()
    {
        Console.WriteLine(threadRunning);
        while (threadRunning)
        {
            MethodInvoker mi = delegate { timeLabel.Text = TimeWriterSingleton.Instance.OutputTime(); };
            Invoke(mi);
        }
    }

    private void Form1_Load(object sender, EventArgs e)
    {
        thread = new Thread(Loop);
        thread.Start();
    }

    private void Form1_FormClosing(object sender, FormClosingEventArgs e)
    {
        threadRunning = false;
        thread.Join();
    }
}

4 个答案:

答案 0 :(得分:0)

您的DataRowView drv = (DataRowView)dataGridView1.CurrentRow.DataBoundItem; DataRow dr = drv.Row; int indexToTable = dgvDataTable.Table.Rows.IndexOf(dr); 阻止了GUI线程,而另一个线程中的Join正在等待您的GUI线程处理该代理。

快速解决方法是使用Invoke代替BeginInvoke,从而发布而不是发送窗口消息。

或者,不要加入。该代码的目的是为了清理自己,为什么要关心线程何时死掉?

第三个修复方法是通过InvokeThread.Abort直接删除该主题。它可能会跳过一些清理工作,但您的特定代码不应该关注,重点是退出。

编辑:使用Environment.Exit的工作代码如下:

BeginInvoke

原始代码的问题在于它的运行速度与CPU允许的速度一样快,将消息队列填充到GUI线程无法跟上的程度。与简单地向队列添加数字相比,更新Windows控件非常昂贵。所以我在UI更新之间添加了一个暂停,让GUI线程呼吸。

对于downvoters,我很好奇你为什么要这样做。我所说的都不是事实错误。

答案 1 :(得分:0)

我决定改用计时器。代码现在看起来像这样,应用程序可以运行:

public partial class Form1 : Form
{
    private System.Timers.Timer timer;

    public Form1()
    {
        InitializeComponent();

        timer = new System.Timers.Timer(60000);
    }

    private void Form1_Load(object sender, EventArgs e)
    {
        timeLabel.Text = TimeWriterSingleton.Instance.OutputTime();
        timer.Elapsed += TimerElapsed;
        timer.Enabled = true;
    }

    private void TimerElapsed(object sender, ElapsedEventArgs e)
    {
        timeLabel.Text = TimeWriterSingleton.Instance.OutputTime();
    }
}

答案 2 :(得分:0)

实际上使用BeginInvoke()并不是一个坏主意。它可能看起来像这样:

private void Form1_Load(object sender, EventArgs e)
{
    thread = new Thread(() => Loop(this));
    thread.Start();
}

private void Loop(Form1 form)
{
    while (threadRunning && !form.IsDisposed)
    {
        MethodInvoker mi = delegate() { timeLabel.Text = /* Some text */ ; };
        BeginInvoke(mi);

        // Let sleep some time...
        Thread.Sleep(1);
    } 
}

private void Form1_FormClosing_1(object sender, FormClosingEventArgs e)
{
    threadRunning = false;
    thread.Join();
}

答案 3 :(得分:-1)

我打算提出更复杂的建议,但你所做的事情非常简单,所以这是一个简单的答案。

使用ThreadPool线程代替线程,只需使用{{3}}线程完成工作,并在表单结束事件中删除thread.Join()

ThreadPool线程是后台线程,并在应用程序关闭时自动终止。

您的问题是,您在UI线程上尝试Invoke方法,但当您退出thread.Join()时有效阻止了用户界面线程,直到您的工作线程退出。所以你自己管了。欢迎来到多线程世界。

此外,如果您发现自己使用了线程,那么您可能做错了什么。你应该使用任务。它更容易,并且通过取消令牌,您可以参与合作取消。