我似乎无法在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();
}
}
答案 0 :(得分:0)
您的DataRowView drv = (DataRowView)dataGridView1.CurrentRow.DataBoundItem;
DataRow dr = drv.Row;
int indexToTable = dgvDataTable.Table.Rows.IndexOf(dr);
阻止了GUI线程,而另一个线程中的Join
正在等待您的GUI线程处理该代理。
快速解决方法是使用Invoke
代替BeginInvoke
,从而发布而不是发送窗口消息。
或者,不要加入。该代码的目的是为了清理自己,为什么要关心线程何时死掉?
第三个修复方法是通过Invoke
或Thread.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()
时有效阻止了用户界面线程,直到您的工作线程退出。所以你自己管了。欢迎来到多线程世界。
此外,如果您发现自己使用了线程,那么您可能做错了什么。你应该使用任务。它更容易,并且通过取消令牌,您可以参与合作取消。