Begininvoke执行顺序的问题

橘子皮... 2015-10-07 01:19:35
多线程,如果以下这句话是在子线程里执行的,而go是public static变量的话,
public static int go = 0;

主线程{ 调用子线程 }

子线程{
//A语句
this.BeginInvoke(new Action(() =>
{
Go ++; //B语句
}));
//C语句
执行顺序是ABC还是ACB
}

我的问题,在子线程里执行顺序是ACB还是ABC ???
...全文
502 13 打赏 收藏 转发到动态 举报
写回复
用AI写文章
13 条回复
切换为时间正序
请发表友善的回复…
发表回复
phommy 2015-10-08
  • 打赏
  • 举报
回复
当在主线程里BeginInvoke时,顺序永远是ACB BeginInvoke原理是向自己发送一条消息,当前方法执行完之前,程序是没有机会跑到消息回圈的 一个例外:如果C中包含Application.DoEvents,则C执行过程中就会去执行B了,顺序是ACBC 如果是在工作线程调用BeginInvoke就很难说了,只能保证先BeginInvoke的语句先被执行,因为消息回圈会按收到消息的顺序处理消息。不过我解释不了为什么4L的实验1得到了非常有规律的结果
APP开发王 2015-10-08
  • 打赏
  • 举报
回复
两个线程哪个先执行时未知的,依赖于操作系统的线程调度机制。
_lee_chong 2015-10-08
  • 打赏
  • 举报
回复
既然是在子线程中begininvoke,顺序理论上来说当然不一定,取决于主线程当前的情况;
但是实际过程中有极大的可能是:b会先执行一点,然后再执行c;
-----------------------------
不过。。。。讨论这个有啥意义么。。。如果你需要c先就invoke,既然用begininvoke那自然是不能在乎谁先谁后了
crystal_lz 2015-10-08
  • 打赏
  • 举报
回复
引用 10 楼 crystal_lz 的回复:
[quote=引用 9 楼 crystal_lz 的回复:]
[quote=引用 6 楼 phommy 的回复:]
当在主线程里BeginInvoke时,顺序永远是ACB
BeginInvoke原理是向自己发送一条消息,当前方法执行完之前,程序是没有机会跑到消息回圈的
一个例外:如果C中包含Application.DoEvents,则C执行过程中就会去执行B了,顺序是ACBC

如果是在工作线程调用BeginInvoke就很难说了,只能保证先BeginInvoke的语句先被执行,因为消息回圈会按收到消息的顺序处理消息。不过我解释不了为什么4L的实验1得到了非常有规律的结果

第一个实验 是因为 启动了一个线程 而这个线程有10毫秒的时间片 在这10毫秒内 远远足够执行10次循环 而里面的begininvoke 是需要让主线程来执行的 所以 时间片在我启动的线程上 在我启动的线程的时间片内 主线程是没有机会执行的
当我 10 次循环执行完毕后 时间片切换 到了主线程 所以刚才的十次 begininvoke 一次性出来了[/quote]
如果 在我的那个循环里面不止是 10 次循环 而是n次 足以让10毫秒执行不完的话 那么 打印结果 就不会是 ac ac ac...然后全部的 b...
因为10毫秒后 时间片切换 来到了主线程 那么在主线程的10毫秒时间片内 会去执行刚才的begininvoke 然后时间片继续切换 又来到了 我启动的线程 然后会继续执行刚才没有执行完的线程 直到完成为止
所以打印情况 可能会是
ac
ac
...
ac
b
b
b
...
ac
ac
...[/quote]

这个测试 和我上面刚才说的基本一直 但是还是很不准确 因为自己写的WriteLine会影响到测试结果 所以 有 abc 这样的情况出现了
tcmakebest 2015-10-08
  • 打赏
  • 举报
回复
讨论B和C哪个先没有意义,如果有特定的要求还是要使用同步代码控制的.
crystal_lz 2015-10-08
  • 打赏
  • 举报
回复
引用 9 楼 crystal_lz 的回复:
[quote=引用 6 楼 phommy 的回复:] 当在主线程里BeginInvoke时,顺序永远是ACB BeginInvoke原理是向自己发送一条消息,当前方法执行完之前,程序是没有机会跑到消息回圈的 一个例外:如果C中包含Application.DoEvents,则C执行过程中就会去执行B了,顺序是ACBC 如果是在工作线程调用BeginInvoke就很难说了,只能保证先BeginInvoke的语句先被执行,因为消息回圈会按收到消息的顺序处理消息。不过我解释不了为什么4L的实验1得到了非常有规律的结果
第一个实验 是因为 启动了一个线程 而这个线程有10毫秒的时间片 在这10毫秒内 远远足够执行10次循环 而里面的begininvoke 是需要让主线程来执行的 所以 时间片在我启动的线程上 在我启动的线程的时间片内 主线程是没有机会执行的 当我 10 次循环执行完毕后 时间片切换 到了主线程 所以刚才的十次 begininvoke 一次性出来了[/quote] 如果 在我的那个循环里面不止是 10 次循环 而是n次 足以让10毫秒执行不完的话 那么 打印结果 就不会是 ac ac ac...然后全部的 b... 因为10毫秒后 时间片切换 来到了主线程 那么在主线程的10毫秒时间片内 会去执行刚才的begininvoke 然后时间片继续切换 又来到了 我启动的线程 然后会继续执行刚才没有执行完的线程 直到完成为止 所以打印情况 可能会是 ac ac ... ac b b b ... ac ac ...
crystal_lz 2015-10-08
  • 打赏
  • 举报
回复
引用 6 楼 phommy 的回复:
当在主线程里BeginInvoke时,顺序永远是ACB BeginInvoke原理是向自己发送一条消息,当前方法执行完之前,程序是没有机会跑到消息回圈的 一个例外:如果C中包含Application.DoEvents,则C执行过程中就会去执行B了,顺序是ACBC 如果是在工作线程调用BeginInvoke就很难说了,只能保证先BeginInvoke的语句先被执行,因为消息回圈会按收到消息的顺序处理消息。不过我解释不了为什么4L的实验1得到了非常有规律的结果
第一个实验 是因为 启动了一个线程 而这个线程有10毫秒的时间片 在这10毫秒内 远远足够执行10次循环 而里面的begininvoke 是需要让主线程来执行的 所以 时间片在我启动的线程上 在我启动的线程的时间片内 主线程是没有机会执行的 当我 10 次循环执行完毕后 时间片切换 到了主线程 所以刚才的十次 begininvoke 一次性出来了
老秋先生 2015-10-08
  • 打赏
  • 举报
回复
常规下是acb。因为本身begin就不是立刻马上去执行的事情,当然也有abc的情况,主要是在C语句执行时间长了
ajianchina 2015-10-07
  • 打赏
  • 举报
回复
引用 3 楼 wowfiowow 的回复:
你这个写法和直接 this.Invoke有区别没?
是的,结果一样,会等待B执行完毕后才执行下面的语句,也就是说结果按ABC执行。 关于你最开始的问题,4楼实测做的不错,我刚才也进行实测,结果倒不是线程调度的问题,更重要的是B与C各自的执行时长,Begininvoke异步执行的方法待调度给予执行线程,只是慢后C一点点时间开始执行,关键还是看B跟C执行的是什么方法,看哪个先执行完毕决定最后顺序。
宝_爸 2015-10-07
  • 打赏
  • 举报
回复
我觉得答案是不一定吧。因为你在其他线程调用的BeginInvoke, 而BeginInvoke内部是实现是在主线程中,this所在的线程。 两个线程哪个先执行时未知的,依赖于操作系统的线程调度机制。
crystal_lz 2015-10-07
  • 打赏
  • 举报
回复
答案是不一定的 begininvoke 是等调用线程空闲的时候 才会去调用他

上面是一种情况 很直接 但是 下面的情况

上面两段代码 运行效果 完全不一样
在第一段代码中 都是在Console 所以没有空余时间 直到线程完毕后 begininvoke 才有空余时间 所以一次性全部打印出来了
而第二段代码中有了 sleep 所以 当sleep的时候 线程就有空闲时间了 所以 begininvoke 得以有机会执行
所以 答案是不确定的 得看你的 A 和 C 是什么样子的语句
如果你的 A 和 C 都是很占用cpu时间的 那么 begininvoke 就很难有机会去执行 或者说等cpu切换时间片的时候 就有机会去执行
如果你的 A 和 C 是不怎么占用 cpu 时间的 那么 它就有可能会有机会去执行
ajianchina 2015-10-07
  • 打赏
  • 举报
回复
答案:ACB 只有当调用的子线程执行完毕后,才会轮到异步委托方法执行。 不够,你可以使用EndInvoke,检索由传递的 IAsyncResult 表示的异步操作的返回值来让B在C之前执行: this.EndInvoke(this.BeginInvoke(new Action(() => { Go++; //B语句 }))); 这样的结果是ABC
橘子皮... 2015-10-07
  • 打赏
  • 举报
回复
引用 1 楼 ajianchina 的回复:
答案:ACB 只有当调用的子线程执行完毕后,才会轮到异步委托方法执行。 不够,你可以使用EndInvoke,检索由传递的 IAsyncResult 表示的异步操作的返回值来让B在C之前执行: this.EndInvoke(this.BeginInvoke(new Action(() => { Go++; //B语句 }))); 这样的结果是ABC
你这个写法和直接 this.Invoke有区别没?

110,571

社区成员

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

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

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