跨线程调用event的问题

beiyehu1307 2017-07-21 07:43:59
文字描述能力差,用代码表示吧:
class A{
public delegate void SomeEventHandler(Object sender, SomeEventArgs e);
public event SomeEventHandler Some;
private void RaiseSome(){
Some?.Invoke(this,new SomeEventArgs());
}
}
A a = new A();
class B{
public void OnSomeEvent(Object sender, SomeEventArgs e){
DoSomething();
}
private void DoSomething(){
Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
}
}

现在有几个不同的线程,分别执行了下面这段代码:
        B b = new B();
a.Some+=b.OnSomeEvent;

然后,某个线程调用a.RaiseSome()
这样,所有的b.DoSomething()都是由该线程执行的。
我想让绑定事件的那几个线程分别执行DoSomething(),而不是由调用a.RaiseSome()的线程去执行,该如何实现?
...全文
371 15 打赏 收藏 转发到动态 举报
写回复
用AI写文章
15 条回复
切换为时间正序
请发表友善的回复…
发表回复
wang_peng_yl 2017-07-24
  • 打赏
  • 举报
回复
在那几个线程里 B b = new B(); a.Some+=b.OnSomeEvent; a.RaiseSome() 这样写不行么
beiyehu1307 2017-07-24
  • 打赏
  • 举报
回复
引用 14 楼 wang_peng_yl 的回复:
在那几个线程里 B b = new B(); a.Some+=b.OnSomeEvent; a.RaiseSome() 这样写不行么
你没理解我的意思,可能是我表述不清楚。 a.RaiseSome()是在一个后台线程里执行的耗时的任务,而不是由其他几个线程执行的。 这样的话,Invoke之后,B的DoSomething()是由A的线程来完成的,但是我需要让B的线程来完成。 类似于BackgroundWorker
SoulRed 2017-07-23
  • 打赏
  • 举报
回复
QT的signal-slot 反应非常迟缓,比回调低好几个层次。c# 里sendmsg你可以试一下
beiyehu1307 2017-07-23
  • 打赏
  • 举报
回复
引用 10 楼 xian_wwq 的回复:
[quote=引用 7 楼 beiyehu1307 的回复:] [quote=引用 5 楼 sp1234 的回复:] [quote=引用 2 楼 beiyehu1307 的回复:] 是UI线程,但是事先不知道是哪个控件,而且事件不止注册了一个方法。线程需要响应用户操作,自然不能通过死循环来完成。
既然“事先不知道是哪个控件”,那么你此时根本就没有基本的必要的知识去纠结在哪一个线程需要操作控件的问题。等你知道要用哪一个控件输入输出时,再来纠结什么UI线程问题;不知道要用哪一个控件的时候不要空洞地担心天会塌下来。[/quote] 1楼的问题是简化版本,完整的情况如下。 1楼的类A会被好几个窗体使用,这几个窗体都需要创建后台线程去调用A做一些事情。在A做事情的途中以及结束之后,均会向窗体报告进度,并且窗体再去更新一大堆UI。(不使用BackGroundWorker,因为有时候A做一件事情需要同时通知好几个窗体) 因此说,对于类A而言,事先不知道是哪个控件。A.Some事件会绑定好几个窗体的函数。 而且,希望让A封装好后就不要改了,以后窗体有增删的时候不更改A的代码。 因为在Qt里,用Signal-Slot时可以指定是发送信号的线程还是接收信号的槽来执行槽函数,很方便,可以实现我上述需求,所以我在想.net里如何实现类似的思路。 [/quote] 感觉这个问题本身和跨线程没有太大关联 lz去搜下C#观察者模式 [/quote] 1楼的代码就是用event实现的观察者模式。我反对5、6楼的观点并且想去找到这个解决方案,正是为了让Subject不关心Observer的实现。但是我需要让属于Observer的线程去执行代码,而不是让Subject所在线程依次执行Observer代码,也不是让Subject新开一堆线程去执行Observer的代码(比如说Observer是UI,有线程安全问题。但这只是一个比方,还可能存在别的场景,所以说5、6楼比较歪)。 而我的这个需求,在Qt里可以用Signal-Slot里的QueuedConnection直接解决,所以我想了解C#里有没有类似的机制。
beiyehu1307 2017-07-23
  • 打赏
  • 举报
回复
Qt的Signal-Slot真是一个方便又不错的机制,可惜在其他平台上没有可以直接拿来用的等价机制。 以"C# QueuedConnection" 关键词Google之,得到了一个解决方案:SynchronizationContext。虽然实现是麻烦了点,不过好歹是个解决方案。 另外,实名反对5楼、6楼观点。这种不讲OOP的观点我实在难以接受。
xian_wwq 2017-07-23
  • 打赏
  • 举报
回复
引用 7 楼 beiyehu1307 的回复:
[quote=引用 5 楼 sp1234 的回复:] [quote=引用 2 楼 beiyehu1307 的回复:] 是UI线程,但是事先不知道是哪个控件,而且事件不止注册了一个方法。线程需要响应用户操作,自然不能通过死循环来完成。
既然“事先不知道是哪个控件”,那么你此时根本就没有基本的必要的知识去纠结在哪一个线程需要操作控件的问题。等你知道要用哪一个控件输入输出时,再来纠结什么UI线程问题;不知道要用哪一个控件的时候不要空洞地担心天会塌下来。[/quote] 1楼的问题是简化版本,完整的情况如下。 1楼的类A会被好几个窗体使用,这几个窗体都需要创建后台线程去调用A做一些事情。在A做事情的途中以及结束之后,均会向窗体报告进度,并且窗体再去更新一大堆UI。(不使用BackGroundWorker,因为有时候A做一件事情需要同时通知好几个窗体) 因此说,对于类A而言,事先不知道是哪个控件。A.Some事件会绑定好几个窗体的函数。 而且,希望让A封装好后就不要改了,以后窗体有增删的时候不更改A的代码。 因为在Qt里,用Signal-Slot时可以指定是发送信号的线程还是接收信号的槽来执行槽函数,很方便,可以实现我上述需求,所以我在想.net里如何实现类似的思路。 [/quote] 感觉这个问题本身和跨线程没有太大关联 lz去搜下C#观察者模式
beiyehu1307 2017-07-23
  • 打赏
  • 举报
回复
所以有人知道该怎么做吗?
beiyehu1307 2017-07-21
  • 打赏
  • 举报
回复
引用 3 楼 StratosBlue 的回复:
[quote=引用 2 楼 beiyehu1307 的回复:] [quote=引用 1 楼 StratosBlue 的回复:] 控件的话可以在OnSomeEvent中使用Invoke让代码在控件的线程中执行; 非控件的话。。在线程中实现一个循环检查标记或信号的东西,在OnSomeEvent执行时改变标记或者发送可以执行的信号。我觉得是这样的。
是UI线程,但是事先不知道是哪个控件,而且事件不止注册了一个方法。线程需要响应用户操作,自然不能通过死循环来完成。 [/quote] 没有想象到你程序的逻辑。。。。。。。。。[/quote] 7楼有更详细的描述
beiyehu1307 2017-07-21
  • 打赏
  • 举报
回复
引用 5 楼 sp1234 的回复:
[quote=引用 2 楼 beiyehu1307 的回复:] 是UI线程,但是事先不知道是哪个控件,而且事件不止注册了一个方法。线程需要响应用户操作,自然不能通过死循环来完成。
既然“事先不知道是哪个控件”,那么你此时根本就没有基本的必要的知识去纠结在哪一个线程需要操作控件的问题。等你知道要用哪一个控件输入输出时,再来纠结什么UI线程问题;不知道要用哪一个控件的时候不要空洞地担心天会塌下来。[/quote] 1楼的问题是简化版本,完整的情况如下。 1楼的类A会被好几个窗体使用,这几个窗体都需要创建后台线程去调用A做一些事情。在A做事情的途中以及结束之后,均会向窗体报告进度,并且窗体再去更新一大堆UI。(不使用BackGroundWorker,因为有时候A做一件事情需要同时通知好几个窗体) 因此说,对于类A而言,事先不知道是哪个控件。A.Some事件会绑定好几个窗体的函数。 而且,希望让A封装好后就不要改了,以后窗体有增删的时候不更改A的代码。 因为在Qt里,用Signal-Slot时可以指定是发送信号的线程还是接收信号的槽来执行槽函数,很方便,可以实现我上述需求,所以我在想.net里如何实现类似的思路。
  • 打赏
  • 举报
回复
你写的 RaiseSome 方法里边那一行代码,在你自己根本不知道要操作哪一个控件的时候,为什么要胡乱地纠结什么 Invoke 语句呢? 等你真正把思路“落地”时候,也就是知道要操作哪一个控件的时候,自然就知道该 Invoke/BeginInvoke 哪里去了。其实这个知识很简单,就是不要以幻想来编程,而要踏实严谨地根据一步步的基本知识规则编程。
  • 打赏
  • 举报
回复
引用 2 楼 beiyehu1307 的回复:
是UI线程,但是事先不知道是哪个控件,而且事件不止注册了一个方法。线程需要响应用户操作,自然不能通过死循环来完成。
既然“事先不知道是哪个控件”,那么你此时根本就没有基本的必要的知识去纠结在哪一个线程需要操作控件的问题。等你知道要用哪一个控件输入输出时,再来纠结什么UI线程问题;不知道要用哪一个控件的时候不要空洞地担心天会塌下来。
  • 打赏
  • 举报
回复
引用 楼主 beiyehu1307 的回复:
我想让绑定事件的那几个线程分别执行DoSomething(),而不是由调用a.RaiseSome()的线程去执行,该如何实现?
放下对线程的纠结不好吗?当前线程该改什么干什么,干完了就结束,根本不应该死等什么东西。纠结于是哪一个线程回调的、一定要把当前线程死等什么东西,目的何在?
Anonymous477 2017-07-21
  • 打赏
  • 举报
回复
引用 2 楼 beiyehu1307 的回复:
[quote=引用 1 楼 StratosBlue 的回复:] 控件的话可以在OnSomeEvent中使用Invoke让代码在控件的线程中执行; 非控件的话。。在线程中实现一个循环检查标记或信号的东西,在OnSomeEvent执行时改变标记或者发送可以执行的信号。我觉得是这样的。
是UI线程,但是事先不知道是哪个控件,而且事件不止注册了一个方法。线程需要响应用户操作,自然不能通过死循环来完成。 [/quote] 没有想象到你程序的逻辑。。。。。。。。。
beiyehu1307 2017-07-21
  • 打赏
  • 举报
回复
引用 1 楼 StratosBlue 的回复:
控件的话可以在OnSomeEvent中使用Invoke让代码在控件的线程中执行; 非控件的话。。在线程中实现一个循环检查标记或信号的东西,在OnSomeEvent执行时改变标记或者发送可以执行的信号。我觉得是这样的。
是UI线程,但是事先不知道是哪个控件,而且事件不止注册了一个方法。线程需要响应用户操作,自然不能通过死循环来完成。
Anonymous477 2017-07-21
  • 打赏
  • 举报
回复
控件的话可以在OnSomeEvent中使用Invoke让代码在控件的线程中执行; 非控件的话。。在线程中实现一个循环检查标记或信号的东西,在OnSomeEvent执行时改变标记或者发送可以执行的信号。我觉得是这样的。

110,567

社区成员

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

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

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