关于多线程操作,无法同步执行的疑惑

yanele 2013-08-07 04:33:18
环境:VS2008+C#+WinForm程序
界面有一保存按钮,执行过程很费时,希望能给用户一些友好显示,自然想到要用进度条;
希望在执行主方法时,进度条也同时显示,并逐步增长的过程。现在主方法与进度条方法都已经写好,单独运行可以成功。但希望达到的效果始终无法实现。

1、进度条与主方法,都有可能涉及到对界面控件的操作,为防止出现<线程间操作无效: 从不是创建控件“”的线程访问它。>这样的错误,进度条主要代码采用了委托:
/// <summary>
/// 进度条委托方法
/// </summary>
/// <param name="ipos"></param>
private void SetProgressBarDelegate(int ipos)
{
if (this.InvokeRequired)
{
this.Invoke(new DelegateIntoInt(this.SetProgressBarDelegate), new object[] { ipos });
}
else
{
base.toolStripProgressBar1.Value = Convert.ToInt32(ipos);
}
}

此时,主方法没有采用进度条这种this.Invoke方式,如果不包含界面控件操作,运行正常。如果加上界面控件操作,就会报错<线程间操作无效: 从不是创建控件“”的线程访问它。>,然后如法炮制,将主方法也改成下面这种:
/// <summary>
/// 执行主方法
/// </summary>
private void DoMainMethodDelegate()
{
if (this.InvokeRequired)
{
this.Invoke(new DelegateIntoNull(this.myMainMethod), new object[] { });
}
}

在保存按钮的主要代码如下:
this.proBarThread = new Thread(new ThreadStart(this.SetToolStripProgressBar));
this.proBarThread.Start();
//执行主线程方法
this.mainThread = new Thread(new ThreadStart(this.DoMainMethodDelegate));
this.mainThread.IsBackground = true;//后台线程
this.mainThread.Start();

结果运行程序,虽不报错了,但两个线程效果并未同时运行,而是将主方法执行完了,才执行的进度条。

本人愚钝,实在不知道问题出在哪里,请大家帮忙指导一下,不甚感激!
...全文
157 9 打赏 收藏 转发到动态 举报
写回复
用AI写文章
9 条回复
切换为时间正序
请发表友善的回复…
发表回复
yanele 2013-09-06
  • 打赏
  • 举报
回复
参考如下网址:
http://www.cnblogs.com/hnfxs/p/3192009.html
qldsrx 2013-08-07
  • 打赏
  • 举报
回复
引用 3 楼 yanele 的回复:
按2楼的说法,主函数myMainMethod,直接放入线程执行,不能用this.BeginInvoke方法,而是将其中涉及到界面操作的部分单独封装出来,调用this.BeginInvoke来执行? 如果是这样,我myMainMethod函数控制界面的地方有点多,方法前,方法中,方法后都有相应的控制,而且都是待程序执行到某一步才执行界面操作,如果用this.BeginInvoke调用,又如何判断主方法执行到哪一步了,才能执行?
界面控制的地方多的话,你也只能见到一处封装一处了,要提高点编程效率的话,可以使用匿名方法和匿名委托,直接在函数中任意地方嵌入。至于你所谓的外部控制是多余的,既然是多线程执行,就不能考虑外部的控制加入,所有需要执行的UI操作要通过委托方式传递给你的myMainMethod函数,执行中适当的时候用this.BeginInvoke调用,当然,你不需要判断InvokeRequired属性,那个完全多余,即使已经处于UI线程,你再使用this.BeginInvoke调用你之前封装好的委托,也没任何错误。 最后要提醒下,这里所谓的this是当前类,如果是WinForm下面使用,自然是没错误,但是如果你在自定义类里面封装方法时使用,就肯定会出错了,所以可以考虑上下文同步类来处理UI同步处理的委托。详情参考线程之间的通讯---SynchronizationContext,这个类是处理UI同步操作的最佳方案,但是却很少有人知道。
  • 打赏
  • 举报
回复
SetToolStripProgressBar不知道你这里面做了什么? 感觉你这个 没必要用两个线程 直接在DoMainMethodDelegate 里面按进度调用 SetProgressBarDelegate就行了啊。
人生导师 2013-08-07
  • 打赏
  • 举报
回复
参考这个文章的解释和实现:http://www.cnblogs.com/zhili/archive/2013/05/11/EAP.html
请叫我卷福 2013-08-07
  • 打赏
  • 举报
回复
所有的控件均由 UI线程负责(也就是main进入的线程) 不需要你另外开辟线程来操作它
请叫我卷福 2013-08-07
  • 打赏
  • 举报
回复
后台处理任务 前台更新界面 没必要使用两个线程 void btn1_Click() { Thread th = new Thread((ThreadStart)delegate() { //处理任务1 this.Invoke((Action)delegate() //建议这儿使用 this.Invoke 不要使用 BeginInvoke 不然界面更新和实际工作进度可能不同步 { this.ProgressBar.Value = 10; }); //处理任务2 this.Invoke((Action)delegate() { this.ProgressBar.Value = 20; }); //处理任务3 this.Invoke((Action)delegate() { this.ProgressBar.Value = 30; }); // ... }); th.Start(); } Backgroundworker 不是控件 如果使用它 意思一样 把你逻辑代码 写进DoWork事件处理程序 根本不需要ReportProgress back.DoWork += DoWorkCallBack; void DoWorkCallBack(...) { //处理任务1 this.Invoke((Action)delegate() //建议这儿使用 this.Invoke 不要使用 BeginInvoke 不然界面更新和实际工作进度可能不同步 { this.ProgressBar.Value = 10; }); //处理任务2 this.Invoke((Action)delegate() { this.ProgressBar.Value = 20; }); //处理任务3 this.Invoke((Action)delegate() { this.ProgressBar.Value = 30; }); // ... } back.RunWorkAsync();
yanele 2013-08-07
  • 打赏
  • 举报
回复
按2楼的说法,主函数myMainMethod,直接放入线程执行,不能用this.BeginInvoke方法,而是将其中涉及到界面操作的部分单独封装出来,调用this.BeginInvoke来执行? 如果是这样,我myMainMethod函数控制界面的地方有点多,方法前,方法中,方法后都有相应的控制,而且都是待程序执行到某一步才执行界面操作,如果用this.BeginInvoke调用,又如何判断主方法执行到哪一步了,才能执行?
qldsrx 2013-08-07
  • 打赏
  • 举报
回复
引用 1 楼 cheery_an 的回复:
用System.ComponentModel.BackgroundWorker不行吗?他有ReportProgress方法和ProgressChanged事件
别把那个弱智的控件拿来谈。 楼主犯了2个错误: 第一是回调不能用this.Invoke,而必须用this.BeginInvoke,否则就容易死锁线程,除非某个地方必须卡住,待主线程的执行完毕后才继续执行,那时才需要用this.Invoke,在异步执行的线程中,this.Invoke的调用将等待主线程执行后,才会执行后面的代码,而this.BeginInvoke只是告诉主线程你要执行这部分代码,然后异步线程立刻执行后面的代码去了。 第二是主方法中全部回调就变成了同步执行了,压根没用到异步执行。你需要改写myMainMethod函数,将里面涉及到界面操作的部分单独封装,调用this.BeginInvoke来执行。
cheery_an 2013-08-07
  • 打赏
  • 举报
回复
用System.ComponentModel.BackgroundWorker不行吗?他有ReportProgress方法和ProgressChanged事件

110,548

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧