Begininvoke中嵌套Invoke发生了阻塞,求解决

qq405165798 2016-04-05 01:17:54
为什么有这样的区别?
正确的调用方式要如何确定?
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WindowsFormsApplication35
{
public partial class Form2 : Form
{

public Form2()
{
InitializeComponent();
Button btn1 = new Button();
btn1.Text = "btn1"; btn1.Dock = DockStyle.Left;
btn1.Click += this.button1_Click;
this.Controls.Add(btn1);
Button btn2 = new Button();
btn2.Text = "btn2"; btn2.Dock = DockStyle.Left;
btn2.Click += this.button2_Click;
this.Controls.Add(btn2);
}


/// <summary>
/// 可以正确执行
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button1_Click(object sender, EventArgs e)
{
((Button)sender).Text = "Running...";
dlg_void_void pf = new dlg_void_void(SetFormText);
var aysncRst = this.BeginInvoke(pf);
this.EndInvoke(aysncRst);
((Button)sender).Text = "Complete";
}
/// <summary>
/// 在执行后阻塞在SetFormText()的 this.Invoke(pf);
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button2_Click(object sender, EventArgs e)
{
((Button)sender).Text = "Running...";
dlg_void_void pf = new dlg_void_void(SetFormText);
var aysncRst = pf.BeginInvoke(null, null);
pf.EndInvoke(aysncRst);
((Button)sender).Text = "Complete";

}
delegate void dlg_void_void();
private void SetFormText()
{
if (this.InvokeRequired)
{
dlg_void_void pf = new dlg_void_void(SetFormText);
this.Invoke(pf);
return;
}

var sum = 0;
for (int i = 0; i < 10; i++)
{
sum += i;
}
this.Text = sum.ToString();
}
}
}
...全文
365 12 打赏 收藏 转发到动态 举报
写回复
用AI写文章
12 条回复
切换为时间正序
请发表友善的回复…
发表回复
qq405165798 2016-04-19
  • 打赏
  • 举报
回复
引用 9 楼 tcmakebest 的回复:
在主线程调用 this.BeginInvoke 是要在主线程执行代码, 所以不会产生新线程, 会等待当前的 Click 结束再执行 而 this.EndInvoke 肯定作了特殊处理, 知道要等待的对象也是在主线程, 那直接执行就行了.
this.BeginInvoke this.EndInvoke 的异步用法网上一堆,原理也基本了解. 唯一搞不明的就是为啥与 pf.EndInvoke会有那么大区别. pf.EndInvoke到底什么时候能用. 仁兄好像没有明白我到底哪里不明白, 切了很多刀,都没切到菜上. 不过给乐于助人点个赞.
qq405165798 2016-04-19
  • 打赏
  • 举报
回复
引用 10 楼 sp1234 的回复:
如果要使用 UI 线程执行 BeginInvoke,那么就要保证所有动态加载的控件都是通过 UI 线程而加载的,并且 BeginInvoke 前边都是控件,也就是 Control.Beginvoke 而不是胡乱找个什么对象就执行 Begininvoke。 第二,实际上你写的代码一点也没有理解异步操作的概念。真正的 EndInvoke 语句是写在 BeginInvoke 语句的回调操作中的,这才叫做异步。而你用同步的编程思路,用异步语句来模拟,等于自欺欺人。“死”得很正常。
大神出现,前来跪拜. 回答真是精准. 最后的打脸更是精彩.
  • 打赏
  • 举报
回复
如果要使用 UI 线程执行 BeginInvoke,那么就要保证所有动态加载的控件都是通过 UI 线程而加载的,并且 BeginInvoke 前边都是控件,也就是 Control.Beginvoke 而不是胡乱找个什么对象就执行 Begininvoke。 第二,实际上你写的代码一点也没有理解异步操作的概念。真正的 EndInvoke 语句是写在 BeginInvoke 语句的回调操作中的,这才叫做异步。而你用同步的编程思路,用异步语句来模拟,等于自欺欺人。“死”得很正常。
tcmakebest 2016-04-16
  • 打赏
  • 举报
回复
在主线程调用 this.BeginInvoke 是要在主线程执行代码, 所以不会产生新线程, 会等待当前的 Click 结束再执行 而 this.EndInvoke 肯定作了特殊处理, 知道要等待的对象也是在主线程, 那直接执行就行了.
qq405165798 2016-04-16
  • 打赏
  • 举报
回复
引用 5 楼 tcmakebest 的回复:
两个 BeginInvoke 撞脸了不是同一类. 懂不懂 在主线程 EndInvoke 时阻塞了, 而 BeginInvoke 产生的线程又要绕回到主线程, 主线程不共享, 产生了互相等待的情况.
十分感谢大侠的持续回答. "在主线程 EndInvoke 时阻塞了, 而 BeginInvoke 产生的线程又要绕回到主线程, 主线程不共享, 产生了互相等待的情况"这句话对两种情况同时适用!! 为什么第一种情况this.EndInvoke(aysncRst);就不会相互等待,第二种情况 pf.EndInvoke(aysncRst);就会等待???????????? 这两种写法不都是在主线程等待吗? 这是两种的唯一区别啊.为什么现象就是截然不同??
qq405165798 2016-04-16
  • 打赏
  • 举报
回复
引用 6 楼 tcmakebest 的回复:
如果要显示结果, 可以给 BeginInvoke 传回调函数, 在回调函数中显示 Complete
这个我明白,这个例子只是用最简单的代码展现疑问. 回调函数的方法我明白的,而且相关资料很多.
tcmakebest 2016-04-13
  • 打赏
  • 举报
回复
如果要显示结果, 可以给 BeginInvoke 传回调函数, 在回调函数中显示 Complete
tcmakebest 2016-04-13
  • 打赏
  • 举报
回复
两个 BeginInvoke 撞脸了不是同一类. 懂不懂 在主线程 EndInvoke 时阻塞了, 而 BeginInvoke 产生的线程又要绕回到主线程, 主线程不共享, 产生了互相等待的情况.
qq405165798 2016-04-13
  • 打赏
  • 举报
回复
引用 1 楼 tcmakebest 的回复:
两种用法的 BeginInvoke 来处是不一样的, 第二种是产生线程的又会调用 Invoke, 与 EndInvoke 同在主线程发生阻塞. 如果要用 BeginXXX 就不要立即在同一个线程中用 EndXXX, 最好是在 AsyncCallback 回调中用.
我奇怪的是,, 正常的阻塞应该不超过10ms,这个Invoke中的阻塞永远不会结束,貌似是死了. 这两种调用方法,都是BeginInvoke开始,都会在产生的线程中调用 Invoke,都在主线程中EndInvoke. 为什么第一种只要等10ms就完成,第二种就永久的卡死了呢?
qq405165798 2016-04-13
  • 打赏
  • 举报
回复
引用 2 楼 shingoscar 的回复:
private void SetFormText() { if (this.InvokeRequired) { dlg_void_void pf = new dlg_void_void(SetFormText); this.Invoke(pf); return; } var sum = 0; for (int i = 0; i < 10; i++) { sum += i; } this.Text = sum.ToString(); } 搞不明白,都已经Invoke了,为何还要判断一遍
因为在做SetFormText()的时候,只知道将来要被多线程调用,没想到是这种Invoke的调用.
Poopaye 2016-04-05
  • 打赏
  • 举报
回复
private void SetFormText() { if (this.InvokeRequired) { dlg_void_void pf = new dlg_void_void(SetFormText); this.Invoke(pf); return; } var sum = 0; for (int i = 0; i < 10; i++) { sum += i; } this.Text = sum.ToString(); } 搞不明白,都已经Invoke了,为何还要判断一遍
tcmakebest 2016-04-05
  • 打赏
  • 举报
回复
两种用法的 BeginInvoke 来处是不一样的, 第二种是产生线程的又会调用 Invoke, 与 EndInvoke 同在主线程发生阻塞. 如果要用 BeginXXX 就不要立即在同一个线程中用 EndXXX, 最好是在 AsyncCallback 回调中用.

110,538

社区成员

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

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

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