我有相当多的编程知识,但这是我第一次在C#上使用多线程应用程序,所以我正在寻求有关我的问题的帮助。
首先是代码,
public frmCEX()
{
InitializeComponent();
refreshTicker();
}
private void btnRefresh_Click(object sender, EventArgs e)
{
refreshTicker();
}
private void refreshTicker()
{
ssStatus.Text = "Updating ticker..";
btnRefresh.Text = "Updating";
btnRefresh.Enabled = false;
ssUpdated.Text = "Last updated: -";
APIManager apim = new APIManager();
Ticker tk = apim.getTicker();
//blablabla, do some work
ssUpdated.Text = "Last updated: " + DateTime.Now.ToString();
ssStatus.Text = "";
btnRefresh.Text = "Refresh";
btnRefresh.Enabled = true;
}
private void cbxRefresh_CheckedChanged(object sender, EventArgs e)
{
if (cbxRefresh.Checked)
{
Thread thread1 = new Thread(() => BGRefreshThread(Convert.ToInt32(nupRefreshSecs.Value)));
thread1.Start();
}
else
{
// IF REFRESH CHECKBOX IS UNCHECKED, STOP THE THREAD THAT IS REFRESHING
}
}
private void BGRefreshThread(int delay)
{
refreshTicker();
System.Threading.Thread.Sleep(delay * 1000);
}
我的主要问题在于cbxRefresh_CheckedChanged
方法,基本上,这是如何工作的,当用户检查主UI中的“自动刷新”复选框时,checkedchanged方法将创建一个新线程{{1}在后台运行并刷新自动收报机,一旦再次取消选中该复选框,它将结束刷新自动收报机的线程。
但是,我在线程启动时遇到问题,因为一旦BGRefreshThread
方法结束,当下次取消选中该复选框时,该线程就不再存在于上下文中。
有人可以建议我如何让这个工作吗?对于多线程编程来说真的很陌生。
**编辑:我找到了解决这个问题的方法,但是现在,当新创建的线程试图调用“refreshTicker”时,它会更新主UI上的标签和按钮(位于主线程上),它给了我这个错误:
跨线程操作无效:从>创建线程以外的线程访问控制'btnRefresh'。
对此有何建议?**
答案 0 :(得分:1)
首先,线程变量应该是实例成员,因此您可以随时访问它。
我做什么来优雅地停止线程:在创建和启动线程之前,我创建了一个ManualResetEvent
,我用它来表示线程退出:
private ManualResetEvent m_stopThread = new ManualResetEvent(false);
要停止线程,我在代码中的某处设置事件并等待线程结束:
m_stopThread.Set();
m_myThread.Join();
线程的代码需要考虑停止:
while (true)
{
// Stop the thread if the handle is set after 1 ms
if (m_stopThread.WaitOne(1, false))
break;
// Do some work
}
答案 1 :(得分:0)
您需要将线程保存在不超出范围的变量中。
private Thread thread1;
private void cbxRefresh_CheckedChanged(object sender, EventArgs e)
{
if (cbxRefresh.Checked)
{
thread1 = new Thread(() => BGRefreshThread(Convert.ToInt32(nupRefreshSecs.Value)));
thread1.Start();
}
else
{
thread1.Abort();
}
}
请注意,有一些检查缺失,中止不是结束线程的好方法。