C#多线程技术(二)
2010-02-22 01:06 ubunoon 阅读(383) 评论(0) 编辑 收藏 举报上一篇中讲述了简单的C#多线程程序编写,应该说并不具备太多的难点,这个程序中,我们将编写一个比较特殊的线程,两个线程需要操作同一个List<int>对象:
2 List<int> elements = new List<int>();
3 public ThreadCollection(){
4 elements.Add(10);
5 elements.Add(20);
6 }
7
8 public void Run()
9 {
10 Thread.Sleep(1000);
11 foreach( int item in elements){
12 Console.WriteLine("Item (" + item + " ) ");
13 Thread.Sleep(1000);
14 }
15
16 }
17
18 public void Add()
19 {
20 Thread.Sleep(1500);
21 elements.Add(30);
22 }
23
24 }
25
26
27 ThreadCollection coll = new ThreadCollection();
28 Thread thread3 = new Thread(
29 new ThreadStart(coll.Run)
30 );
31 Thread thread4 = new Thread(
32 new ThreadStart(coll.Add)
33 );
34
35 thread3.Start();
36 thread4.Start();
37
这个时候,系统会抛出一个InvalidOperationException的异常。显然,我们需要修改程序,一种方法是获取elments的一个镜像(snapshot),对镜像(snapshot)进行操作,这个时候,数据内容被获取出来,用到的类为:
System.Collections.ObjectModel.ReadOnlyCollection。将原先的foreach语句修改为:
foreach(int item in new ReadOnlyCollection<int>(elements)){...}
这种方法是对elements中的元素进行标记,elements中不允许插入数据,因此系统仍旧会爆出错误。彻底的解决方法是使用lock锁块语句,使用lock将需要进行锁的变量传递进来,然后用{}操作需要lock的语句。示例代码如下:
2 foreach (int item in elements)
3 {
4 Console.WriteLine("Item (" + item + " ) ");
5 Thread.Sleep(1000);
6 }
7 }
8
9 ///////////////////////////////////////////////////////////
10
11 lock(elements)
12 {
13 elements.Add(30);
14 }
此外,将elements数据拷贝出来,然后对拷贝出来的数据进行遍历,这个时候,由于写入和读数据是两个完全不同的对象,不存在同步问题,因此,也可以很好运行:
2 lock(elements){
3 items = elements.ToArray();
4 }
5 foreach (int item in items)
6 {
7 Console.WriteLine("Item (" + item + " ) ");
8 Thread.Sleep(1000);
9 }
显然,这种方法,在数据量较大的情况i下,拷贝的时候需要花费较长的时间,并且需要占据更多的内存。但这种方法容易维护与理解。有时候,这种方法也非常有效,因为拷贝的时候,可能还没有写入较多的数据,数据仍旧在后台进行写入,但前台已经可以对部分这些数据进行操作,而不会明显影响后台操作数据。
*
* Copyright (c) 2011 Ubunoon.
* All rights reserved.
*
* email: netubu#gmail.com replace '#' to '@'
* http://www.cnblogs.com/ubunoon
* 欢迎来邮件定制各类验证码识别,条码识别,图像处理等软件
* 推荐不错的珍珠饰品,欢迎订购 * 宜臣珍珠(淡水好珍珠) */