C# 拷贝数组的几种方式.docx_第1页
C# 拷贝数组的几种方式.docx_第2页
C# 拷贝数组的几种方式.docx_第3页
C# 拷贝数组的几种方式.docx_第4页
C# 拷贝数组的几种方式.docx_第5页
已阅读5页,还剩15页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

C# 拷贝数组的几种方式C#中数组复制有多种方法数组间的复制,int pins = 9,3,4,9;int alias = pins;这里出了错误,也是错误的根源,以上代码并没有出错,但是根本不是复制,因为pins和alias都是引用,存在于堆栈中,而数据9,3,4,3是一个int对象存在于堆中,int alias = pins;只不过是创建另一个引用,alias和pins同时指向9,3,4,3,当修改其中一个引用的时候,势必影响另一个。复制的意思是新建一个和被复制对象一样的对象,在C#语言中应该有如下4种方法来复制。 方法一:使用for循环int pins = 9,3,7,2int copy = new intpins.length;for(int i =0;i!=copy.length;i+)copyi = pinsi;方法二:使用数组对象中的CopyTo()方法int pins = 9,3,7,2int copy2 = new intpins.length;pins.CopyTo(copy2,0);方法三:使用Array类的一个静态方法Copy()int pins = 9,3,7,2int copy3 = new intpins.length;Array.Copy(pins,copy3,copy.Length);方法四:使用Array类中的一个实例方法Clone(),可以一次调用,最方便,但是Clone()方法返回的是一个对象,所以要强制转换成恰当的类类型。int pins = 9,3,7,2int copy4 = (int )pins.Clone();方法五:string student1 = $, $, c, m, d, 1, 2, 3, 1, 2, 3 ;string student2 = 0, 1, 2, 3, 4, 5, 6, 6, 1, 8, 16,10,45, 37, 82 ;ArrayList student = new ArrayList(); foreach (string s1 in student1) student.Add(s1); foreach (string s2 in student2) student.Add(s2);string copyAfter = (string)student.ToArray(typeof(string);两个数组合并,最后把合并后的结果赋给copyAfter数组,这个例子可以灵活变通,很多地方可以用。首先说明一下,数组是引用类型的,所以注意不要在复制时复制了地址而没有复制数值哦!其实在复制数组的时候,一定要用new在堆中开辟一块新的空间专门用于存放数组,这样才是有效的。(1)int pins = 9, 3, 7, 2 ;int copy=new intpins.length;for (int i = 0; i copy.length; i+)copyi = pinsi;(2)int copy = new intpins.Length;pins.CopyTo(copy, 0);(3) Int pins= new int49,3,7,2;Int alias=pins;注意这种复制只是一种引用而已,只是把数据的地址传递给了alias数组,所以不太推荐这种方式来复制数组;(4)Array.Copy(pins,copy,copy.Length)(5)Int copy=(int)pins.Clone();这里说明一下为什么要用到int的强制类型转换,原因就在于Clone的结果类型是object的,所以需要强制转换为intObject类其实就是我们所有类的基类。C#数组中CopyTo()和Clone()的区别(转)CopyTo()和Clone()1.CopyTo()和Clone()相信大多数C#程序员都有查阅MSDN的好习惯,但是MSDN中提到这两个方法最大的区别就是:一个方法创建了一个新Array对象,一个方法只是复制了Array引用.这句话本身没有错误,而且也正是他们的区别所在.只是这样会让人感到很迷惑.到底是什么区别呢?这里还是先说说他们的共同点:CopyTo()和Clone()都属于浅拷贝,这一点是毋庸置疑的.对于浅拷贝:如果数组中的成员为值类型(如:int,float,double,byte等),则完全复制数值到目标数组中,如果是引用类型(如用户自定义类型:class Student,class People,或者是类库中的类类型:ArrayList等),则指复制引用给目标数组.那么CopyTo()和Clone()方法的区别是什么呢?其实他们的区别,也就是MSDN上说的最大的区别就是用法上的区别.我们可以在VS弹出智能提示的时候看看他们的返回值,CopyTo()的返回值是void,使用方法如下Array1.CopyTo(Array2,0);其中Array2必须是一个已经实例化的数组.而Clone()的返回值是object.使用方法如下Array2 = Array1.Clone();其中Array2不必实例化.这样,我相信理解这两个方法的区别就很容易了.本质上并没有什么区别.都属于浅拷贝.如果拷贝所有的数组,就是用Clone().但是如果只是拷贝一部分,就可以选择CopyTo()了,CopyTo()的参数提示是这样的CopyTo(Array array,int Index).第二个参数index(索引)是指明从数组中的第几个对象开始复制.2.浅拷贝和深拷贝的区别.如上面所说的,浅拷贝对于值类型则复制值,对于引用类型则复制对象的引用(类似于指针).深拷贝则是完完全全的创建一个个新对象.对原来数组中的所有对象全部创建新对象.对新数组中的修改不会影响原来数组中的值或对象.但是如何实现深拷贝呢?.NET库中似乎没有深拷贝的方法.这和实现深拷贝的原理有关系.若用户希望实现深拷贝.希望出现两个完全一样但又互不影响的数组.则必须自己写方法,对原数组中的每个对象实现拷贝,层层深入,直到这个对象中的对象中的对象中的对象为值类型为止,因为只有值类型才是完全拷贝,对一个值进行修改不会影响另一个相同的值.这么说又有点难理解了. 1. 深拷贝是指源对象与拷贝对象互相独立,其中任何一个对象的改动都不会对另外一个对象造成影响。举个例子,一个人名叫张三,后来用他克隆(假设法律允许)了另外一个人,叫李四,不管是张三缺胳膊少腿还是李四缺胳膊少腿都不会影响另外一个人。比较典型的就是Value(值)对象,如预定义类型Int32,Double,以及结构(struct),枚举(Enum)等。 考虑以下写法int source = int.MaxValue;/(1)初始化源对象为整数的最大值2,147,483,647int dest = source;/(2)赋值,内部执行深拷贝dest = 1024;/(3)对拷贝对象进行赋值source = 2048;/(4)对源对象进行赋值首先(2)中将source赋给dest,执行了深拷贝动作,其时dest和source的值是一样的,都是int.MaxValue;(3)对dest进行修改,dest值变为1024,由于是深拷贝,因此不会运行source,source仍然是int.MaxValue;(4)对source进行了修改,同样道理,dest仍然是1024,同时int.MaxValue的值也不变,仍然是2,147,483,647;只有source变成了2048。再考虑以下写法struct Pointpublic int X;public int Y;public Point(int x, int y)X = x;Y = y;Point source = new Point(10, 20);Point dest = source;dest.X = 20当dest.X属性变成20后,source的X属性仍然是102. 浅拷贝是指源对象与拷贝对象共用一份实体,仅仅是引用的变量不同(名称不同)。对其中任何一个对象的改动都会影响另外一个对象。举个例子,一个人一开始叫张三,后来改名叫李四了,可是还是同一个人,不管是张三缺胳膊少腿还是李四缺胳膊少腿,都是这个人倒霉。比较典型的就有Reference(引用)对象,如Class(类)。考虑以下写法class Pointpublic int X;public int Y;public Point(int x, int y)X = x;Y = y;Point source = new Point(10, 20);Point dest = source;dest.X = 20;由于Point现在是引用对象,因此Point dest=source的赋值动作实际上执行的是浅拷贝,最后的结果应该是source的X字段值也变成了20。即它们引用了同一个对象,仅仅是变量明source和dest不同而已。3. 引用对象的浅拷贝原理引用对象之间的赋值之所以执行的是浅拷贝动作,与引用对象的特性有关,一个引用对象一般来说由两个部分组成(1)一个具名的Handle,也就是我们所说的声明(如变量)(2)一个内部(不具名)的对象,也就是具名Handle的内部对象。它在Manged Heap(托管堆)中分配,一般由新增引用对象的New方法是进行创建如果这个内部对象已被创建,那么具名的Handle就指向这个内部对象在Manged Heap中的地址,否则就是null(从某个方面来讲,如果这个具名的handle可以被赋值为null,说明这是一个引用对象,当然不是绝对)。两个引用对象如果进行赋值,它们仅仅是复制这个内部对象的地址,内部对象仍然是同一个,因此,源对象或拷贝对象的修改都会影响对方。这也就是浅拷贝4. 引用对象如何进行深拷贝由于引用对象的赋值仅仅是复制具名Handle(变量)指向的地址,因此要对引用对象进行深拷贝就要重新创建一份该对象的实例,并对该对象的字段进行逐一赋值,如以下写法class Pointpublic int X;public int Y;public Point(int x, int y)X = x;Y = y;Point source = new Point(10, 20);Point dest = new Point(source.X, source.Y);/或以下写法/Point dest = new Point()/dest.X = source.X/dest.Y = source.Y其时,source和dest就是两个互相独立的对象了,两者的修改都不会影响对方5一些需要注意的东西(1):String字符串对象是引用对象,但是很特殊,它表现的如值对象一样,即对它进行赋值,分割,合并,并不是对原有的字符串进行操作,而是返回一个新的字符串对象(2):Array数组对象是引用对象,在进行赋值的时候,实际上返回的是源对象的另一份引用而已;因此如果要对数组对象进行真正的复制(深拷贝),那么需要新建一份数组对象,然后将源数组的值逐一拷贝到目的对象中在C#中怎么部分复制数组?Array.Copy()方法有四种重载,其中有一个重载可以指定从数组的第几个元素开始复制,复制多少个。具体用法如下:public static void Copy( Array sourceArray, /包含要复制的数据 long sourceIndex, /64 位整数,它表示 sourceArray 中复制开始处的索引 Array destinationArray, /目的数组 long destinationIndex, /64 位整数,它表示 destinationArray 中存储开始处的索引 long length /64 位整数,它表示要复制的元素数目)C# 数组复制的另外两种方式。字节偏移复制与安全复制。代码如下:static void Main(string args)int src = new 1, 2, 3, 4, 5, 6 ;const int destLen = 4;/目标数组大小int int_size = sizeof(int);/用于获取值类型的字节大小。int dest = new intdestLen;/只支持基元类型,按字节偏移复制Buffer.BlockCopy(src, (src.Length - destLen) * int_size, dest, 0, destLen * int_size);foreach (var i in dest)Console.Write(i + );Console.WriteLine(n-);string srcstr = new A, B, C, D, E, F ;object destobj = new objectsrc.Length - 2;/移除的元素个数const int dellen = 2;/保证不破坏目标数组的元素(回滚)。不装箱、拆箱、或向下转换,否则报错。/如果srcstr改为src则报错,因为装箱。Array.ConstrainedCopy(srcstr, dellen, destobj, 0, srcstr.Length - dellen);foreach (var s in destobj)Console.Write(s + );效果如下:C#中的浅拷贝与深拷贝浅拷贝:如果数组中的成员为值类型(如:int,float,double,byte等),则完全复制数值到目标数组中,如果是引用类型(如用户自定义类型:class Student,class People,或者是类库中的类类型:ArrayList等),则指复制引用给目标数组。文字有时候不如代码来得容易理解.但是这里也许用图更容易理解,看下图:假定创建一个学生类数组Student,然后浅拷贝到另一个学生类数组Student1中从图中很容易看出所谓的浅拷贝对于引用类型,仅仅只是复制引用.通过一个数组修改内存中的值会影响另一个数组对内存对象的引用。Array 类中的CopyTo和Clone函数都属于浅拷贝。深拷贝则是完完全全的创建一个个新对象.对原来数组中的所有对象全部创建新对象.对新数组中的修改不会影响原来数组中的值或对象。C#线程锁使用全功略前两篇简单介绍了线程同步lock,Monitor,同步事件EventWaitHandler,互斥体Mutex的基本用法,在此基础上,我们对 它们用法进行比较,并给出什么时候需要锁什么时候不需要的几点建议。最后,介绍几个FCL中线程安全的类,集合类的锁定方式等,做为对线程同步系列的完善 和补充。1.几种同步方法的区别lock和Monitor是.NET用一个特殊结构实现的,Monitor对象是完全托管的、完全可移植的,并且在操作系统资源要求方 面可能更为有效,同步速度较快,但不能跨进程同步。lock(Monitor.Enter和Monitor.Exit方法的封装),主要作用是锁定临界区,使临 界区代码只能被获得锁的线程执行。Monitor.Wait和Monitor.Pulse用于线程同步,类似信号操作,个人感觉使用比较复杂,容易造成死 锁。互斥体Mutex和事件对象EventWaitHandler属于内核对象,利用内核对象进行线程同步,线程必须要在用户模式和内核模 式间切换,所以一般效率很低,但利用互斥对象和事件对象这样的内核对象,可以在多个进程中的各个线程间进行同步。互斥体Mutex类似于一个接力棒,拿到接力棒的线程才可以开始跑,当然接力棒一次只属于一个线程(Thread Affinity),如果这个线程不释放接力棒(Mutex.ReleaseMutex),那么没办法,其他所有需要接力棒运行的线程都知道能等着看热 闹。EventWaitHandle 类允许线程通过发信号互相通信。 通常,一个或多个线程在 EventWaitHandle 上阻止,直到一个未阻止的线程调用 Set 方法,以释放一个或多个被阻止的线程。2.什么时候需要锁定首先要理解锁定是解决竞争条件的,也就是多个线程同时访问某个资源,造成意想不到的结果。比如,最简单的情况是,一个计数器,两个线程 同时加一,后果就是损失了一个计数,但相当频繁的锁定又可能带来性能上的消耗,还有最可怕的情况死锁。那么什么情况下我们需要使用锁,什么情况下不需要 呢?1)只有共享资源才需要锁定只有可以被多线程访问的共享资源才需要考虑锁定,比如静态变量,再比如某些缓存中的值,而属于线程内部的变量不需要锁定。 2)多使用lock,少用Mutex如果你一定要使用锁定,请尽量不要使用内核模块的锁定机制,比如.NET的Mutex,Semaphore,AutoResetEvent和 ManuResetEvent,使用这样的机制涉及到了系统在用户模式和内核模式间的切换,性能差很多,但是他们的优点是可以跨进程同步线程,所以应该清 楚的了解到他们的不同和适用范围。3)了解你的程序是怎么运行的实际上在web开发中大多数逻辑都是在单个线程中展开的,一个请求都会在一个单独的线程中处理,其中的大部分变量都是属于这个线程的,根本没有必要考虑锁 定,当然对于ASP.NET中的Application对象中的数据,我们就要考虑加锁了。4)把锁定交给数据库数 据库除了存储数据之外,还有一个重要的用途就是同步,数据库本身用了一套复杂的机制来保证数据的可靠和一致性,这就为我们节省了很多的精力。保证了数据源 头上的同步,我们多数的精力就可以集中在缓存等其他一些资源的同步访问上了。通常,只有涉及到多个线程修改数据库中同一条记录时,我们才考虑加锁。 5)业务逻辑对事务和线程安全的要求这 条是最根本的东西,开发完全线程安全的程序是件很费时费力的事情,在电子商务等涉及金融系统的案例中,许多逻辑都必须严格的线程安全,所以我们不得不牺牲 一些性能,和很多的开发时间来做这方面的工作。而一般的应用中,许多情况下虽然程序有竞争的危险,我们还是可以不使用锁定,比如有的时候计数器少一多一, 对结果无伤大雅的情况下,我们就可以不用去管它。3.InterLocked类Interlocked 类提供了同步对多个线程共享的变量的访问的方法。如果该变量位于共享内存中,则不同进程的线程就可以使用该机制。互锁操作是原子的,即整个操作是不能由相 同变量上的另一个互锁操作所中断的单元。这在抢先多线程操作系统中是很重要的,在这样的操作系统中,线程可以在从某个内存地址加载值之后但是在有机会更改 和存储该值之前被挂起。我们来看一个InterLock.Increment()的例子,该方法以原子的形式递增指定变量并存储结果,示例如下:class InterLockedTestpublic static Int64 i = 0;public static void Add()for (int i = 0; i 100000000; i+)Interlocked.Increment(ref InterLockedTest.i);/InterLockedTest.i = InterLockedTest.i + 1;public static void Main(string args)Thread t1 = new Thread(new ThreadStart(InterLockedTest.Add);Thread t2 = new Thread(new ThreadStart(InterLockedTest.Add);t1.Start();t2.Start();t1.Join();t2.Join();Console.WriteLine(InterLockedTest.i.ToString();Console.Read();输出结果200000000,如果InterLockedTest.Add()方法中用注释掉的语句代替Interlocked.Increment() 方法,结果将不可预知,每次执行结果不同。InterLockedTest.Add()方法保证了加1操作的原子性,功能上相当于自动给加操作使用了 lock锁。同时我们也注意到InterLockedTest.Add()用时比直接用+号加1要耗时的多,所以说加锁资源损耗还是很明显的。另外InterLockedTest类还有几个常用方法,具体用法可以参考MSDN上的介绍。4.集合类的同步.NET在一些集合类,比如Queue、ArrayList、HashTable和Stack,已经提供了一个供lock使用的对象SyncRoot。用 Reflector查看了SyncRoot属性(Stack.SynchRoot略有不同)的源码如下:public virtual object SyncRootgetif (this._syncRoot = null)/如果_syncRoot和null相等,将new object赋值给 _syncRoot/Interlocked.CompareExchange方法保证多个线程在使用 syncRoot时是线程安全的Interlocked.CompareExchange(ref this._syncRoot, new object(), null);return this._syncRoot;这里要特别注意的是MSDN提到:从头到尾对一个集合进行枚举本质上并不是一个线程安全的过程。即使一个集合已进行同步,其他线程仍可以修改该集合,这将 导致枚举数引发异常。若要在枚举过程中保证线程安全,可以在整个枚举过程中锁定集合,或者捕捉由于其他线程进行的更改而引发的异常。应该使用下面的代码:Queue使用lock示例Queue q = new Queue();lock (q.SyncRoot)foreach (object item in q)/do something还有一点需要说明的是,集合类提供了一个是和同步相关的方法Synchronized,该 方法返回一个对应的集合类的wrapper类,该类是线程安全的,因为他的大部分方法都用lock关键字进行了同步处理。如HashTable的 Synchronized返回一个新的线程安全的HashTable实例,代码如下:/在多线程环境中只要我们用下面的 方式实例化HashTable就可以了Hashtable ht = Hashtable.Synchronized(new Hashtable();/以下代码是.NET Framework Class Library实现,增加对 Synchronized的认识HostProtection(SecurityAction.LinkDemand, Synchronization=true)public static Hashtable Synchronized(Hashtable table)if (table = null)throw new ArgumentNullException(table);return new SyncHashtable(table);/SyncHashtable的几个常用方法,我们可以看到内部实现都加了lock关键字 保证线程安全public override void Add(object key, object value)lock (this._table.SyncRoot)this._table.Add(key, value);public override void Clear()lock (this._table.SyncRoot)this._table.Clear();public override void Remove(object key)lock (this._table.SyncRoot)this._table.Remove(key);线程同步是一个非常复杂的话题,这里只是根据公司的一个项目把相关的知识整理出来,作为工作的一种总结。这些同步方法的使用场景是怎样的?究竟有哪些细微 的差别?还有待于进一步的学习和实践。lock 关键字将语句块标记为临界区,方法是获取给定对象的互斥锁,执行语句,然后释放该锁。此语句的形式如下:复制Object thisLock = new Object();lock (thisLock) / Critical code section有关更多信息,请参见 线程同步(C# 编程指南)。备注lock 确保当一个线程位于代码的临界区时,另一个线程不进入临界区。如果其他线程试图进入锁定的代码,则它将一直等待(即被阻止),直到该对象被释放。线程处理(C# 编程指南) 这节讨论了线程处理。lock 调用块开始位置的 Enter 和块结束位置的 Exit。通常,应避免锁定 public 类型,否则实例将超出代码的控制范围。常见的结构 lock (this)、lock (typeof (MyType) 和 lock (myLock) 违反此准则: 如果实例可以被公共访问,将出现 lock (this) 问题。 如果 MyType 可以被公共访问,将出现 lock (typeof (MyType) 问题。 由于进程中使用同一字符串的任何其他代码将共享同一个锁,所以出现 lock(“myLock”) 问题。 最佳做法是定义 private 对象来锁定, 或 private static 对象变量来保护所有实例所共有的数据。下例显示的是在 C# 中使用线程的简单示例。复制/ statements_lock.csusing System;using System.Threading;class ThreadTest public void RunMe() Console.WriteLine(RunMe called); static void Main() ThreadTest b = new ThreadTest(); Thread t = new Thread(b.RunMe); t.Start(); 输出RunMe called下例使用线程和 lock。只要 lock 语句存在,语句块就是临界区并且 balance 永远不会是负数。/ statements_lock2.csusing System;using System.Threading;class Account private Object thisLock = new Object(); int balance; Random r = new Random(); public Account(int initial) balance = initial; int Withdraw(int amount) / This condition will never be true unless the lock statement / is commented out: if (balance = amount) Console.WriteLine(Balance before Withdrawal : + balance); Console.WriteLine(Amount to Withdraw : - + amount); balance = balance - amount; Console.WriteLine(Balance after Withdrawal : + balance); return amount; else return 0; / transaction rejected public void DoTransactions() for (int i = 0; i 100; i+) Withdraw(r.Next(1, 100); class Test static void Main() Thread threads = new Thread10; Account acc = new Account(1000); for (int i = 0; i 10; i+) Thread t = new Thread(new ThreadStart(acc.DoTransactions); threadsi = t; for (int i = 0; i 10; i+) threadsi.Start(); 以下各节描述了在多线程应用程序中可以用来同步资源访问的功能和类。在应用程序中使用多个线程的一个好处是每个线程都可以异步执行。对于 Windows 应用程序,耗时的任务可以在后台执行,而使应用程序窗口和控件保持响应。对于服务器应用程序,多线程处理提供了用不同线程处理每个传入请求的能力。否则,在完全满足前一个请求之前,将无法处理每个新请求。然而,线程的异步特性意味着必须协调对资源(如文件句柄、网络连接和内存)的访问。否则,两个或更多的线程可能在同一时间访问相同的资源,而每个线程都不知道其他线程的操作。结果将产生不可预知的数据损坏。 对于整数数据类型的简单操作,可以用 Interlocked 类的成员来实现线程同步。对于其他所有数据类型和非线程安全的资源,只有使用本主题中的结构才能安全地执行多线程处理。有关多线程编程的背景信息,请参见: 使用线程处理(C# 编程指南) 托管线程处理基本知识 使用线程和线程处理 托管线程处理的最佳做法 lock 关键字lock 关键字可以用来确保代码块完成运行,而不会被其他线程中断。这是通过在代码块运行期间为给定对象获取互斥锁来实现的。 lock 语句以关键字 lock 开头,它有一个作为参数的对象,在该参数的后面还有一个一次只能由一个线程执行的代码块。例如:C#复制public void Function() System.Object lockThis = new System.Object(); lock(lockThis) / Access thread-sensitive resources. 提供给 lock 关键字的参数必须为基于引用类型的对象,该对象用来定义锁的范围。在上例中,锁的范围限定为此函数,因为函数外不存在任何对该对象的引用。严格地说,提供给 lock 的对象只是用来唯一地标识由多个线程共享的资源,所以它可以是任意类实例。然而,实际上,此对象通常表示需要进行线程同步的资源。例如,如果一个容器对象将被多个线程使用,则可以将该容器传递给 lock,而 lock 后面的同步代码块将访问该容器。只要其他线程在访问该容器前先锁定该容器,则对该对象的访问将是安全同步的。通常,最好避免锁定 public 类型或锁定不受应用程序控制的对象实例。例如,如果该实例可以被公开访问,则 lock(this) 可能会有问题,因为不受控制的代码也可能会锁定该对象。这可能导致死锁,即两个或更多个线程等待释放同一对象。出于同样的原因,锁定公共数据类型(相比于对象)也可能导致问题。锁定字符串尤其危险,因为字符串被公共语言运行库 (CLR)“暂留”。这意味着整个程序中任何给定字符串都只有一个实例,就是这同一个对象表示了所有运行的应用程序域的所有线程中的该文本。因此,只要在应用程序进程中的任何位置处具有相同内容的字符串上放置了锁,就将锁定应用程序中该字符串的所有实例。因此,最好锁定不会被暂留的私有或受保护成员。某些类提供专门用于锁定的成员。例如,Array 类型提供 SyncRoot。许多集合类型也提供 SyncRoot。有关 lock 关键字的更多信息,请参见: lock 语句(C# 参考) 如何:对制造者线程和使用者线程进行同步(C# 编程指南)监视器与 lock 关键字类似,监视器防止多个线程同时执行代码块。Enter 方法允许一个且仅一个线程继续执行后面的语句;其他所有线程都将被阻止,直到执行语句的线程调用 Exit。这与使用 lock 关键字一样。事实上,lock 关键字就是用 Monitor 类来实现的。例如:C#复制lock(x) DoSomething();这等效于:C#复制System.Object obj = (System.Object)x;System.Threading.Monitor.Enter(obj);try DoSomething();finally System.Threading.Monitor.Exit(obj);使用 lock 关键字通常比直接使用 Monitor 类更可取,一方面是因为 lock 更简洁,另一方面是因为 lock 确保了即使受保护的代码引发异常,也可以释放基础监视器。这是通过 finally 关键字来实现的,无论是否引发异常它都执行关联的代码块。有关监视器的更多信息,请参见监视器同步技术示例。同步事件和等待句柄使用锁或监视器对于防止同时执行区分线程的代码块很有用,但是这些构造不允许一个线程向另一个线程传达事件。这需要“同步事件”,它是有两个状态(终止和非终止)的对象,可以用来激活和挂起线程。让线程等待非终止的同步事件可以将线程挂起,将事件状态更改为终止可以将线程激活。如果线程试图等待已经终止的事件,则线程将继续执行,而不会延迟。同步事件有两种:AutoResetEvent 和 ManualResetEvent。它们之间唯一的不同在于,无论何时,只要 AutoResetEvent 激活线程,它的状态将自动从终止变为非终止。相反,

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论