线程安全的方式引发事件
2015-08-24 16:03
603 查看
消息发送Helper类(演示用,无任何意义):
调用,消息发送完毕后调用OnCompleted()方法,这在单线程下没有任何问题:
但如果在多线程下对 Completed事件操作时会问题。
为了模拟多线程下的并发,对代码进行了修改:
这时再运行就会出现Object reference not set to an instance of an object 异常。
所以应该以线程安全的方式触发事件,这里用到了Interlocked 类的泛型方法:
public class MessageHelper { /// <summary> /// 消息发送完成 触发的事件 /// </summary> public event EventHandler<MessageEventArgs> Completed; protected virtual void OnCompleted(MessageEventArgs e) { //一般情况都这样触发 if (Completed != null) Completed(this, e); //或者这样触发(不过编译器可能会做优化,和上面代码没什么区别) //var temp = Completed; //if (temp != null) temp(this, e); } /// <summary> /// 发送消息 /// </summary> /// <param name="from">发送人</param> /// <param name="to">接收人</param> /// <param name="content">消息内容</param> public virtual void Send(string from, string to, string content) { Console.WriteLine(string.Format("{0} Send To {1},Message:{2}", from, to, content)); OnCompleted(new MessageEventArgs(from, to, content)); } } public class MessageEventArgs : EventArgs { public MessageEventArgs(string from, string to, string content) { this.From = from; this.To = to; this.Content = content; } public string From { get; set; } public string To { get; set; } public string Content { get; set; } }
调用,消息发送完毕后调用OnCompleted()方法,这在单线程下没有任何问题:
class Program { static void Main(string[] args) { MessageHelper message = new MessageHelper(); message.Completed += message_Completed; message.Send("习大大", "小泉", "小子,轻点嘚瑟!"); Console.ReadKey(); } static void message_Completed(object sender, MessageEventArgs e) { Console.WriteLine("消息发送完毕!"); } }
但如果在多线程下对 Completed事件操作时会问题。
为了模拟多线程下的并发,对代码进行了修改:
static void Main(string[] args) { MessageHelper message = new MessageHelper(); message.Completed += message_Completed; Thread thread1 = new Thread(() => { message.Send("习大大", "小泉", "小子,轻点嘚瑟!"); }); //这个线程只是 移除了事件 Thread thread2 = new Thread(() => { Thread.Sleep(1000); message.Completed -= message_Completed; }); thread1.Start(); thread2.Start(); //message.Send("习大大", "小泉", "小子,轻点嘚瑟!"); Console.ReadKey(); } static void message_Completed(object sender, MessageEventArgs e) { Console.WriteLine("消息发送完毕!"); }
protected virtual void OnCompleted(MessageEventArgs e) { //一般情况都这样触发 if (Completed != null) { Thread.Sleep(2000); //这里是为了等待Completed被移除 Completed(this, e); } //或者这样触发(不过编译器可能会做优化,和上面代码没什么区别) //var temp = Completed; //if (temp != null) temp(this, e); }
这时再运行就会出现Object reference not set to an instance of an object 异常。
所以应该以线程安全的方式触发事件,这里用到了Interlocked 类的泛型方法:
protected virtual void OnCompleted(MessageEventArgs e) { ////一般情况都这样触发 //if (Completed != null) //{ // Thread.Sleep(2000); //这里是为了等待Completed被移除 // Completed(this, e); //} //或者这样触发(不过编译器可能会做优化,和上面代码没什么区别) //var temp = Completed; //if (temp != null) temp(this, e); //线程安全的方式触发事件 EventHandler<MessageEventArgs> temp = Interlocked.CompareExchange<EventHandler<MessageEventArgs>>(ref Completed, null, null); Thread.Sleep(2000);//这里是为了等待Completed被移除 temp(this, e); }
相关文章推荐
- POJ 3020 Antenna Placement 匈牙利算法,最大流解法 难度:1
- firefox HackBar组件模拟请求POST请求
- Coding 两步认证技术介绍
- 解决Fetching android sdk component information加载过久问题
- java中观察者模式
- 递归分析和分治算法
- 小试随机森林(random forest)算法ml
- 信任
- [python] 爬取网站所有的URL
- Cache
- ElasticSearch+LogStash+Kibana+Redis搭建日志管理服务
- Android layer-list 圆角阴影背景
- Gearman介绍、调研、测试与原理分析
- STL学习----入门(1)[iterator]
- 调用[[UIDevice currentDevice] userInterfaceIdiom]==UIUserInterfaceIdiomPad判断设备
- Android Cursor
- Wireshark 与 TCP/IP四层模型
- C++ 入门教程(五) 使用 std::cout 输出和数字分位符的使用
- 学习android 显式Intent和隐式Intent
- 高效实用内存