改善C#程序的157个建议(连载73)

发表于:2011-11-10 10:07

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:陆敏技    来源:51Testing软件测试网采编

  建议73:避免锁定不恰当的同步对象

  在C#中,让线程同步的另一种编码方式就是使用线程锁。线程锁的原理,就是锁住一个资源,使得应用程序在此刻只有一个线程访问该资源。通俗地讲,就是让多线程变成单线程。在C#中,可以将被锁定的资源理解成new出来的普通CLR对象。

  既然需要锁定的资源就是C#中的一个对象,我们就该仔细思考,到底什么样的对象能够成为一个锁对象(也叫同步对象)?在选择同步对象的时候,应当始终注意以下几点:

  1)同步对象在需要同步的多个线程中是可见的同一个对象。

  2)在非静态方法中,静态变量不应作为同步对象。

  3)值类型对象不能作为同步对象。

  4)避免将字符串作为同步对象。

  5)降低同步对象的可见性。

  下面分别详细介绍以上五个注意事项。

  第一个注意事项:需要锁定的对象在多个线程中是可见的,而且是同一个对象。“可见的”这是显而易见的,如果对象不可见,就不能被锁定。“同一个对象”,这也很容易理解,如果锁定的不是同一个对象,那又如何来同步两个对象呢?虽然理解起来简单,但不见得我们在这上面就不会犯错误。为了帮助大家理解本建议的内容,我们先模拟一个必须使用到锁的场景:在遍历一个集合的过程中,同时在另外一个线程中删除集合中的某项。下面这个例子中,如果没有lock语句,将会抛出异常InvalidOperationException:“集合已修改;可能无法执行枚举”:

  1. public partial class FormMain : Form  
  2. {  
  3.     public FormMain()  
  4.     {  
  5.         InitializeComponent();  
  6.     }  
  7.     AutoResetEvent autoSet = new AutoResetEvent(false);  
  8.     List<string> tempList = new List<string>() { "init0", "init1", "init2" };  
  9.     private void buttonStartThreads_Click(object sender, EventArgs e)  
  10.     {  
  11.         object syncObj = new object();  
  12.         Thread t1 = new Thread(() => 
  13.         {  
  14.             //确保等待t2开始之后才运行下面的代码  
  15.             autoSet.WaitOne();  
  16.             lock (syncObj)  
  17.             {  
  18.                 foreach (var item in tempList)  
  19.                 {  
  20.                     Thread.Sleep(1000);  
  21.                 }  
  22.             }  
  23.         });  
  24.         t1.IsBackground = true;  
  25.         t1.Start();  
  26.         Thread t2 = new Thread(() => 
  27.         {  
  28.             //通知t1可以执行代码  
  29.             autoSet.Set();  
  30.             //沉睡1秒是为了确保删除操作在t1的迭代过程中  
  31.             Thread.Sleep(1000);  
  32.             lock (syncObj)  
  33.             {  
  34.                 tempList.RemoveAt(1);  
  35.             }  
  36.         });  
  37.         t2.IsBackground = true;  
  38.         t2.Start();  
  39.     }  
  40. }

  这是一个Winform窗体应用程序,需要演示的功能在按钮的单击事件中。对象syncObj对于线程t1和t2来说,在CLR中肯定是同一个对象。所以,上面的示例运行是没有问题的。

31/3123>
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号