分享

c#中的线程

 simplelam 2014-11-24
在.NET程序设计中,线程是使用Thread类(或Timer类(线程计数器)、ThreadPool类(线程池))来处理的,这些类在System.Threading命名空间中:
using System.Threading;
Thread类:(实现线程的主要方法)一个Thread实例管理一个线程,即执行序列。通过简单实例化一个Thread对象,就可以创建一个线程,然后通过Thread对象提供的方法对线程进行管理。
Timer类:适用于间隔性的完成任务。
ThreadPool:适用于多个小的线程。

Thread类的主要属性
ApartmentState  获取或设置此线程的单元状态。
CurrentContext  获取线程正在其中执行的当前上下文。
CurrentCulture  获取或设置当前线程的区域性。
CurrentPrincipal  获取或设置线程的当前负责人(对基于角色的安全性而言)。
CurrentThread  获取当前正在运行的线程。
CurrentUICulture  获取或设置资源管理器使用的当前区域性以便在运行时查找区域性特定的资源。
ExecutionContext  获取一个 ExecutionContext 对象,该对象包含有关当前线程的各种上下文的信息。  
IsAlive  获取一个值,该值指示当前线程的执行状态。
IsBackground  获取或设置一个值,该值指示某个线程是否为后台线程。
IsThreadPoolThread  获取一个值,该值指示线程是否属于托管线程池。
ManagedThreadId  获取当前托管线程的唯一标识符。
Name  获取或设置线程的名称。
Priority  获取或设置一个值,该值指示线程的调度优先级。
ThreadState  获取一个值,该值包含当前线程的状态。




在使用任何线程类之前,必须定义 System.Threading名称空间。

Thread.Start():启动线程的执行。Thread thread1=new Thread(new ThreadStart( Count ));thread1.Start();其中,Count是将要被新线程执行的函数,它不应包含任何参数和返回值,它即可以是静态的,也可以是非静态的,当它执行完毕后,相应的线程就结束了,其线程对象的IsAlive属性也就被置为false了。

Thread.Suspend():挂起线程,或者如果线程已挂起,则不起作用。Thread类的Suspend方法用来挂起线程,直到调用Resume,此线程才可以继续执行。如果线程已经挂起,那就不会起作用。if (thread.ThreadState = ThreadState.Running ) { thread.Suspend(); }


Thread.Resume():恢复线程,继续已挂起的线程。用来恢复已经挂起的线程,以让它继续执行,如果线程没挂起,也不会起作用。

Thread.Interrupt():中止处于 Wait或者Sleep或者Join 线程状态的线程。

Thread.Join():阻塞调用线程,直到某个线程终止时为止。

Thread.Sleep():将当前线程阻塞指定的毫秒数。如thread.Sleep(1000);就是让线程休眠1秒钟。Sleep(0)表示挂起线程以使其它线程能够运行。

Thread.Abort():以开始终止此线程的过程。如果线程已经在终止,则不能通过Thread.Start()来启动线程。在杀死一个线程前最好先判断它是否还活着(通过IsAlive属性),然后就可以调用Abort方法来杀死此线程。引发 ThreadAbortException。

Thread.ResetAbort():取消为当前线程请求的Abort

Thread.Interrupt():中止处于 Wait或者Sleep或者Join 线程状态的线程。

Thread.GetDomain():返回当前线程正在其中运行的当前域。


AllocateDataSlot  在所有的线程上分配未命名的数据槽。  
AllocateNamedDataSlot  在所有线程上分配已命名的数据槽。  
BeginCriticalRegion  通知宿主执行将要进入一个代码区域,在该代码区域内线程中止或未处理的异常的影响可能会危害应用程序域中的其他任务。  
BeginThreadAffinity  通知宿主托管代码将要执行依赖于当前物理操作系统线程的标识的指令。  
EndCriticalRegion  通知宿主执行将要进入一个代码区域,在该代码区域内线程中止或未处理的异常仅影响当前任务。  
EndThreadAffinity  通知宿主托管代码已执行完依赖于当前物理操作系统线程的标识的指令。  
Equals   已重载。 确定两个 Object 实例是否相等。 (从 Object 继承。)
FreeNamedDataSlot  为进程中的所有线程消除名称与槽之间的关联。  
GetApartmentState  返回一个 ApartmentState 值,该值指示单元状态。  
GetCompressedStack  返回一个 CompressedStack 对象,该对象可用于捕获当前线程的堆栈。  
GetData  在当前线程的当前域中从当前线程上指定的槽中检索值。    
GetDomainID  返回唯一的应用程序域标识符。  
GetHashCode  已重写。 返回当前线程的哈希代码。  
GetNamedDataSlot  查找已命名的数据槽。  
GetType   获取当前实例的 Type。 (从 Object 继承。)    
MemoryBarrier  同步内存。其效果是将缓存内存中的内容刷新到主内存中,从而使处理器能执行当前线程。  
ReferenceEquals   确定指定的 Object 实例是否是相同的实例。 (从 Object 继承。)  
SetApartmentState  在线程启动前设置其单元状态。  
SetCompressedStack  对当前线程应用捕获的 CompressedStack。  
SetData  在当前正在运行的线程上为此线程的当前域在指定槽中设置数据。    
SpinWait  导致线程等待由 iterations 参数定义的时间量。  。  
ToString   返回表示当前 Object 的 String。 (从 Object 继承。)
TrySetApartmentState  在线程启动前设置其单元状态。  
VolatileRead  已重载。 读取字段值。无论处理器的数目或处理器缓存的状态如何,该值都是由计算机的任何处理器写入的最新值。  
VolatileWrite  已重载。 立即向字段写入一个值,以使该值对计算机中的所有处理器都可见。




·优先级:
    Thread类中ThreadPriority属性,它用来设置优先级,但不能保证操作系统会接受该优先级。一个线程的优先级可分为5种。Normal,AboveNormal,BelowNormal,Highest,Lowest。
    thread1.Priority = ThreadPriority.Highest;



.Net的公共语言运行时(CLR)能区分两种不同类型的线程:前台线程和后台线程。
它两者的区别是:应用程序必须运行完所有的前台线程才可以退出;而对于后台线程,应用程序则可以不考虑其是否已经运行完毕而直接退出,所有的后台线程在应用程序退出时会自动结束。
一个线程是前台线程还是后台线程,可以由它的IsBackground属性来决定。



·ThreadState在各种情况下的可能取值如下:
Aborted:线程已停止
AbortRequested:线程的Thread.Abort()方法已被调用,但是线程还未停止
Background:线程在后台执行,与属性Thread.IsBackground有关
Running:线程正在正常运行
Stopped:线程已经被停止
StopRequested:线程正在被要求停止
Suspended:线程已经被挂起(此状态下,可以通过调用Resume()方法重新运行)
SuspendRequested:线程正在要求被挂起,但是未来得及响应
Unstarted:未调用Thread.Start()开始线程的运行
WaitSleepJoin:线程因为调用了Wait(),Sleep()或Join()等方法处于封锁状态


临界区
·Lock关键字:将某个语句块标记为临界区,另一个线程不能进入临界区。
·Interlocked类:为多个线程共享的变量提供原子操作。Increment和Decrement方法递增或递减变量将结果值存储在单个操作中。
·Monitor类:提供同步对象访问的机制。通过向单个线程授予对象锁来控制对象的访问。使用Enter和Exit方法标记临界区的开头和结尾。
   Monitor.Enter(this);//不限时间
   if(Monitor.TryEnter(this,TimeSpan.FromSeconds(30)));//在30秒内获取对象排它锁。

·Monitor类实现加锁与解锁。该类中的方法都是静态的。
Enter:在指定对象上获取排它锁。
TryEnter:试图获取指定对象的排它锁。
Exit:释放指定对象的排它锁。
Wait:释放对象上的锁并阻塞当前线程,直到它重新获取该锁。
Pulse:通知等待队列中的线程锁定对象状态的更改。
PulseAll:通知所有等待线程对象状态的更改。


C#中 lock关键字提供了与Monitoy.Enter和Monitoy.Exit同样的功能,这种方法用在你的代码段不能被其他独立的线程中断的情况。通过对Monitor类的简易封装,lock为同步访问变量提供了一个非常简单的方式,其用法如下:
lock(x)
{
    // 使用x的语句
}
x可以是任何对象或变量,可以在lock前定义一个object x,然后用x作为锁使用该语句,lock语句把变量放在圆括号中,以包装对象,称为独占锁或排它锁。当执行带有lock关键字的复合语句时,独占锁会保留下来。当变量被包装在独占锁中时,其他线程就不能访问该变量。如果在上面的代码中使用独占锁,在执行复合语句时,这个线程就会失去其时间片。如果下一个获得时间片的线程试图访问变量,就会被拒绝。Windows会让其他线程处于睡眠状态,直到解除了独占锁为止。



Synchronization Events

同步时间是一些等待句柄用来通知其他的线程发生了什么事情和资源是可用的。他们有两个状态:signaled and nonsignaled。AutoResetEvent 和 ManualResetEvent就是这种同步事件。

AutoResetEvent Class

这个类可以通知一个或多个线程发生事件。当一个等待线程得到释放时,它将状态转换为signaled。用set方法使它的实例状态变为signaled。但是一旦等待的线程被通知时间变为signaled,它的转台将自动的变为nonsignaled。如果没有线程侦听事件,转台将保持为signaled。此类不能被继承。

ManualResetEvent Class

这个类也用来通知一个或多个线程事件发生了。它的状态可以手动的被设置和重置。手动重置时间将保持signaled状态直到ManualResetEvent.Reset设置其状态为nonsignaled,或保持状态为nonsignaled直到ManualResetEvent.Set设置其状态为signaled。这个类不能被继承。

Interlocked Class

它提供了在线程之间共享的变量访问的同步,它的操作时原子操作,且被线程共享.你可以通过Interlocked.Increment 或 Interlocked.Decrement来增加或减少共享变量.它的有点在于是原子操作,也就是说这些方法可以代一个整型的参数增量并且返回新的值,所有的操作就是一步.你也可以使用它来指定变量的值或者检查两个变量是否相等,如果相等,将用指定的值代替其中一个变量的值.

ReaderWriterLock class

它定义了一种锁,提供唯一写/多读的机制,使得读写的同步.任意数目的线程都可以读数据,数据锁在有线程更新数据时将是需要的.读的线程可以获取锁,当且仅当这里没有写的线程.当没有读线程和其他的写线程时,写线程可以得到锁.因此,一旦writer-lock被请求,所有的读线程将不能读取数据直到写线程访问完毕.它支持暂停而避免死锁.它也支持嵌套的读/写锁.支持嵌套的读锁的方法是ReaderWriterLock.AcquireReaderLock,如果一个线程有写锁则该线程将暂停;

支持嵌套的写锁的方法是ReaderWriterLock.AcquireWriterLock,如果一个线程有读锁则该线程暂停.如果有读锁将容易倒是死锁.安全的办法是使用ReaderWriterLock.UpgradeToWriterLock方法,这将使读者升级到写者.你可以用ReaderWriterLock.DowngradeFromWriterLock方法使写者降级为读者.调用ReaderWriterLock.ReleaseLock将释放锁, ReaderWriterLock.RestoreLock将重新装载锁的状态到调用ReaderWriterLock.ReleaseLock以前.



1.每个窗体都有自己的都在不同的线程上运行,如果需要在窗体之间交互,就需要在线程之间交互。

2.当线程Sleep时,系统就退出执行队列一段时间,当睡眠结束时,系统会产生一个时钟中断,从而
使线程回到执行队列中,从而恢复线程的执行。

3.如果父线程先于子线程结束,那么子线程将在父线程结束的同时被迫结束。Thread.Join()方法使父线程等待,直到子线程结束。
Abort()方法带来的后果是不可恢复的终止线程。

4.起始线程可以称之为主线程,如果所有的前台线程都停止了,那么主线程可以终止,而所有的后台线程都将无条件终止。
后台线程跟前台线程只有一个区别,那就是后台线程不妨碍程序的终止。一旦一个进程所有的前台线程都终止后,CLR
将通过调用任意一个存活中的后台进程的Abort()方法来彻底终止进程。

6.挂起,睡眠(都可称为--阻塞,暂停)
与Thread.Sleep 不同,Thread.Suspend 不会使线程立即停止执行。直到线程到达安全点之后它才可以将该线程挂起。如果线程尚
未启动或已经停止,则它将不能挂起。调用 Thread.Resume 将使另一个线程跳出挂起状态并使该线程继续执行。
一个线程不能对另一个线程调用Sleep ,但是一个线程可以对另一个线程调用Suspend。
还可以使用许多其它的方式来阻塞线程。例如,可以通过调用 Thread.Join 使一个线程等待另一个线程(子线程)停止。使用
Monitor.Wait使一个线程等待访问一个同步对象。

5.关键字lock可以把一段代码定义为互斥段(critical section),互斥段在一个时刻内只允许一个线程进入执行,而其他线程必须等待。
多线程公用一个对象时,就不应该使用lock关键字了,这里Monitor,Monitor提供了使线程共享资源的方案。
Monitor类可以锁定一个对象,一个线程只有得到这把锁才可以对该对象进行操作。
如:
Monitor.Enter(obj);
//现在oQueue对象只能被当前线程操纵了
Monitor.Exit(obj);

6.一个进程开始时至少会有一个主线程 ( 即主执行实例 ) ,这是在系统加载你的程序的时候所创建的主执行流程。
而消息队列则是与线程 ( Thread ) 相关的,在似win2k上一个线程有一个且只有一个消息队列 ( queue ) 与之相对应。
消息队列是在什么时候生成的呢? 在似win2k系统上,从一开始创建线程就已经有了。
一个线程可以创建多个窗体。统发送给这些窗口的消息都统一发送到同一个 消息队列 中,幸亏消息结构中有msg.hwnd指出该条消息与
哪一个窗口相关, DispatchMessage() 函数就是依照这个保证消息分派处理自动化而且不会出错!

7.每个窗体都属于创建它的线程,在一线程中直接访或间接问其它线程中的窗体的方法将导致运行时错误(VS2005)。
解决方法:使用窗体从Control继承而来的Control.Invoke(Delegate)方法。该方法将在创建窗体的线程上执行委托指向的方法。
注意:在VS2003下,可以在一个线程中直接或间接调用另一个线程中的窗体的方法,而不会导致运行时错误。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多