当前位置:文档之家› 托管线程处理

托管线程处理

托管线程处理
托管线程处理

托管线程处理

托管线程处理基本知托管线程处理基本知识识

线程与线程处线程与线程处理理

操作系统使用进程将它们正在执行的不同应用程序分开。线程是操作系统分配处理器时间的基本单元,并且进程中可以有多个线程同时执行代码。每个线程都维护异常处理程序、调度优先级和一组系统用于在调度该线程前保存线程上下文的结构。线程上下文包括为使线程在线程的宿主进程地址空间中无缝地继续执行所需的所有信息,包括线程的 CPU 寄存器组和堆栈。

.NET Framework 将操作系统进程进一步细分为由 System.AppDomain

表示的、称为应用程序域的轻量托管子进程。一个或多个托管线程(由 System.Threading.Thread 表示)可以在同一个托管进程中的一个或任意数目的应用程序域中运行。虽然每个应用程序域都是用单个线程启动的,但该应用程序域中的代码可以创建附加应用程序域和附加线程。其结果是托管线程可以在同一个非托管进程中的应用程序域之间自由移动;您可能只有一个线程在若干应用程序域之间移动。

支持抢先多任务处理的操作系统可以创建多个进程中的多个线程同时执行的效果。它通过以下方式实现这一点:在需要处理器时间的线程之间分割可用处理器时间,并轮流为每个线程分配处理器时间片。当前执行的线程在其时间片结束时被挂起,而另一个线程继续运行。当系统从一个线程切换到另一个线程时,它将保存被抢先的线程的线程上下文,并重新加载线程队列中下一个线程的已保存线程上下文。

时间片的长度取决于操作系统和处理器。由于每个时间片都很小,因此即使只有一个处理器,多个线程看起来似乎也是在同时执行。这实际上就是多处理器系统中发生的情形,在此类系统中,可执行线程分布在多个可用处理器中。

多个线程的优多个线程的优点点

无论如何,要提高对用户的响应速度并且处理所需数据以便几乎同时完成工作,使用多个线程是一种最为强大的技术。在具有一个处理器的计算机上,多个线程可以通过利用用户事件之间很小的时间段在后台处理数据来达到这种效果。例如,在另一个线程正在重新计算同一应用程序中的电子表格的其他部分时,用户可以编辑该电子表格。 无需修改,同一个应用程序在具有多个处理器的计算机上运行时将极大地满足用户的需要。单个应用程序域可以使用多个线程来完成以下任务:

?

通过网络与 Web 服务器和数据库进行通信。 ?

执行占用大量时间的操作。 ?

区分具有不同优先级的任务。例如,高优先级线程管理时间关键的任务,低优先级线程执行其他任务。 ? 使用户界面可以在将时间分配给后台任务时仍能快速做出响应。

多个线程的缺多个线程的缺点点

建议您使用尽可能少的线程,这样可以最大限度地减少操作系统资源的使用,并可提高性能。线程处理还具有在设计应用程序时要考虑的资源要求和潜在冲突。这些资源要求如下所述:

?

系统将为进程、AppDomain 对象和线程所需的上下文信息使用内存。因此,可以创建的进程、AppDomain 对象和线程的数目会受到可用内存的限制。 ?

跟踪大量的线程将占用大量的处理器时间。如果线程过多,则其中大多数线程都不会产生明显的进度。如果大多数当前线程处于一个进程中,则其他进程中的线程的调度频率就会很低。 ?

使用许多线程控制代码执行非常复杂,并可能产生许多 bug 。 ? 销毁线程需要了解可能发生的问题并对那些问题进行处理。

提供对资源的共享访问会造成冲突。为了避免冲突,必须对共享资源进行同步或控制对共享资源的访问。如果在相同或不同的应用程序域中未能正确地使访问同步,则会导致出现一些问题,这些问题包括死锁和争用条件等,其中死锁是指两个线程都停止响应,并且都在等待对方完成;争用条件是指由于意外地出现对两个事件的执行时间的临界依赖性而发生反常的结果。系统提供了可用于协调多个线程之间的资源共享的同步对象。减少线程的数目使同步资源更为容易。

需要同步的资源包括:

?

系统资源(如通信端口)。 ?

多个进程所共享的资源(如文件句柄)。 ? 由多个线程访问的单个应用程序域的资源(如全局、静态和实例字段)。

线程处理与应用程序设线程处理与应用程序设计计

一般情况下,要为不会阻止其他线程的相对较短的任务处理多个线程并且不需要对这些任务执行任何特定调度时,使用 ThreadPool 类是一种最简单的方式。但是,有多个理由创建您自己的线程:

?

如果您需要使一个任务具有特定的优先级。 ?

如果您具有可能会长时间运行(并因此阻止其他任务)的任务。 ?

如果您需要将线程放置到单线程单元中(所有 ThreadPool 线程均处于多线程单元中)。 ?

如果您需要与该线程关联的稳定标识。例如,您应使用一个专用线程来中止该线程,将其挂起或按名称发现它。 ? 如果您需要运行与用户界面交互的后台线程,.NET Framework 2.0 版提供了 BackgroundWorker

组件,该组件可以使用事件与用户界面线程的跨线程封送进行通信。

为多线程处理同步数为多线程处理同步数据据

当多个线程可以调用单个对象的属性和方法时,对这些调用进行同步处理是非常重要的。否则,一个线程可能会中断另一个线程正在执行的任务,使该对象处于一种无效状态。其成员不受这类中断影响的类叫做线程安全类。 “公共语言基础结构”提供了几种可用来同步对实例和静态成员的访问的策略:

?

同步代码区域。可以使用 Monitor 类或此类的编译器支持来仅同步需要此类的代码块,从而提高性能。 ?

手动同步。可以使用 .NET Framework 类库提供的同步对象。请参见 同步基元概述,这部分对 Monitor 类进行了讨论。 ?

同步上下文。可以使用 SynchronizationAttribute 为 ContextBoundObject 对象启用简单的自动同步。 ? Synchronized 属性。Hashtable 和 Queue 等几个类提供了一个可为该类的实例返回线程安全包装的

Synchronized 属性。请参见集合和同步(线程安全)。

前台和后台线前台和后台线程程

托管线程或者是后台线程,或者是前台线程。后台线程不会使托管执行环境处于运行状态,除此之外,后台线程与前台线程是一样的。一旦所有前台线程在托管进程(其中 .exe

文件是托管程序集)中被停止,系统将停止所有后台线程并关闭。 注意注意:: 当运行库因为进程关闭而停止某个后台线程时,不会在该线程中引发异常。但是,当线程是因为 AppDomain.Unload 方法卸载应用程序域而停止时,将同时在后台和前台线程中引发 ThreadAbortException 。

可使用 Thread.IsBackground 属性确定线程是后台线程还是前台线程,或更改其状态。通过将其 IsBackground 属性设置为 true ,可在任何时候将线程更改为后台线程。

重要说明重要说明::

线程的前台或后台状态不影响线程中未处理异常的结果。在 .NET Framework 2.0

版中,前台或后台线程中的未处理异常都将导致应用程序终止。请参见 托管线程中的异常。

属于托管线程池的线程(即其 IsThreadPoolThread 属性为 true

的线程)是后台线程。从非托管代码进入托管执行环境的所有线程都被标记为后台线程。通过创建并启动新的 Thread 对象而生成的所有线程都默认为前台线程。

如果使用一个线程监视活动(例如套接字连接),请将其 IsBackground 属性设置为

true ,以便该线程不会阻止进程终止。

托管线程处理的最佳做托管线程处理的最佳做法法

使用多线程时要考虑以下准则:

?

不要使用 Thread.Abort 终止其他线程。对另一个线程调用 Abort 无异于引发该线程的异常,也不知道该线程已处理到哪个位置。 ?

不要使用 Thread.Suspend 和 Thread.Resume 同步多个线程的活动。请使用 Mutex 、ManualResetEvent 、AutoResetEvent 和 Monitor 。 ?

不要从主程序中控制辅助线程的执行(如使用事件),而应在设计程序时让辅助线程负责等待任务,执行任务,并在完成时通知程序的其他部分。如果辅助线程不阻止,请考虑使用线程池线程。Monitor.PulseAll 在辅助线程阻止的情况下很有用。 ? 不要将类型用作锁定对象。例如,避免在 C# 中使用 lock(typeof(X)) 代码,或在 Visual Basic

中使用 SyncLock(GetType(X)) 代码,或将 Monitor.Enter 和 Type

对象一起使用。对于给定类型,每个应用程序域只有一个 System.Type 实例。如果您锁定的对象的类型是 public ,您的代码之外的代码也可锁定它,但会导致死锁。有关其他信息,请参见可靠性最佳做法。

? 锁定实例时要谨慎,例如,C# 中的 lock(this) 或 Visual Basic 中的

SyncLock(Me)。如果您的应用程序中不属于该类型的其他代码锁定了该对象,则会发生死锁。

? 一定要确保已进入监视器的线程始终离开该监视器,即使当线程在监视器中时发生异常也是如此。C# 的 lock 语句和 Visual Basic 的 SyncLock 语句可自动提供此行为,它们用一个 finally 块来确保调用

Monitor.Exit 。如果无法确保调用 Exit ,请考虑将您的设计更改为使用 Mutex 。Mutex

在当前拥有它的线程终止后会自动释放。

? 一定要针对那些需要不同资源的任务使用多线程,避免向单个资源指定多个线程。例如,任何涉及 I/O

的任务都会从其拥有其自己的线程这一点得到好处,因为此线程在 I/O

操作期间将阻止,从而允许其他线程执行。用户输入是另一种可从专用线程获益的资源。在单处理器计算机上,涉及大量计算的任务可与用户输入和涉及 I/O 的任务并存,但多个计算量大的任务将相互竞争。

? 对于简单的状态更改,请考虑使用 Interlocked 类的方法,而不是 lock 语句(在 Visual Basic 中为

SyncLock )。lock 语句是一个优秀的通用工具,但是 Interlocked

类为必须是原子性的更新提供了更好的性能。如果没有争夺,它会在内部执行一个锁定前缀。在查看代码时,请注意类似于以下示例所示的代码。在第一个示例中,状态变量是递增的: Visual Basic 复制代码 SyncLock lockObject myField += 1 End SyncLock C# 复制代码 lock(lockObject) { myField++; } ? 可以使用 Increment 方法代替 lock 语句,从而提高性能,如下所示: Visual Basic 复制代码 System.Threading.Interlocked.Increment(myField)

C# 复制代码

System.Threading.Interlocked.Increment(myField);

注意注意::

在 .NET Framework 2.0 版中,Add 方法提供增量大于 1 的原子更新。 ? 在第二个示例中,仅当引用类型变量为 null 引用(在 Visual Basic 中为 Nothing )时,它才会被更新。 Visual Basic 复制代码 If x Is Nothing Then SyncLock lockObject If x Is Nothing Then x = y End If End SyncLock End If C# 复制代码 if (x == null) { lock (lockObject) { if (x == null) { x = y; } } } ? 改用 CompareExchange 方法可以提高性能,如下所示:

Visual Basic

复制代码 https://www.doczj.com/doc/1c3084660.html,pareExchange(x, y, Nothing)

C# 复制代码

https://www.doczj.com/doc/1c3084660.html,pareExchange(ref x, y, null);

注意注意::

在 .NET Framework 2.0 版中,CompareExchange

方法具有一个泛型重载,可用于对任何引用类型进行类型安全的替换。

线程处理对象和功线程处理对象和功能能

.NET Framework 提供了许多有助于您创建和管理多线程应用程序的对象。托管线程由 Thread

类表示。ThreadPool 类提供了创建和管理多线程后台任务的简便方法。BackgroundWorker

类为与用户界面交互的任务提供相同的功能。Timer 类按固定的时间间隔执行后台任务。

此外,还有许多用于同步线程活动的类,包括 .NET Framework 2.0 版中引入的 Semaphore 和

EventWaitHandle 类。同步基元概述中对这些类的功能进行了比较

托管线程池

ThreadPool

类为应用程序提供一个由系统管理的辅助线程池,从而使您可以集中精力于应用程序任务而不是线程管理。如果您具有需要后台处理的短期任务,则托管线程池是可以利用多个线程的便捷方式。

对于与用户界面交互的后台任务,.NET Framework 2.0 版还提供了 BackgroundWorker

类,该类可以使用用户界面线程中引发的事件进行通信。

.NET Framework 使用线程池线程实现多种用途,包括异步 I/O 完成、Timer

回调、注册的等待操作、使用委托的异步方法调用以及 https://www.doczj.com/doc/1c3084660.html, 套接字连接。

何时不使用线程池线何时不使用线程池线程程

在以下几种情况下,适合于创建并管理自己的线程而不是使用线程池线程:

?

需要前台线程。 ?

需要使线程具有特定的优先级。 ?

您的任务会导致线程长时间被阻塞。由于线程池具有最大线程数限制,因此大量阻塞的线程池线程可能会阻止任务启动。 ?

需要将线程放入单线程单元。所有 ThreadPool 线程均处于多线程单元中。 ? 您需要具有与线程关联的稳定标识,或使某一线程专用于某一任务。

线程池特征

线程池线程是后台线程。请参见前台和后台线程。每个线程都使用默认堆栈大小,以默认的优先级运行,并处于多线程单元中。

每个进程只有一个线程池对象。

最大线程池线程最大线程池线程数数

可排队到线程池的操作数仅受可用内存的限制;但是,线程池限制进程中可以同时处于活动状态的线程数。默认情况下,限制每个 CPU 可以使用 25 个辅助线程和 1,000 个 I/O 完成线程。

通过使用 GetMaxThreads 和 SetMaxThreads 方法可以控制最大线程数。 注意注意:: 在 .NET Framework 1.0 和 1.1 版中,不能从托管代码中设置线程池大小。承载公共语言运行库的代码可以使用 mscoree.h 中定义的 CorSetMaxThreads 设置该大小。

最小空闲线程最小空闲线程数数

即使是在所有线程都处于空闲状态时,线程池也会维持最小的可用线程数,以便队列任务可以立即启动。将终止超过此最小数目的空闲线程,以节省系统资源。默认情况下,每个处理器维持一个空闲线程。

在启动新的空闲线程之前,线程池具有一个内置延迟(在 .NET Framework 2.0

版中为半秒钟)。应用程序在短期内定期启动许多任务时,空闲线程数的微小增加会导致吞吐量显著增加。将空闲线程数设置得过高会浪费系统资源。

使用 GetMinThreads 和 SetMinThreads 方法可以控制线程池所维持的空闲线程数。

注意注意::

在 .NET Framework 1.0 版中,不能设置最小空闲线程数。

计时器

计时器是使您能够指定要在指定时间调用的委托的轻量对象。线程池中的线程执行等待操作。

使用 Timer 类是非常简单的。需要创建一个 Timer ,将 TimerCallback

委托传递给回调方法;还需要创建一个表示将被传递给回调的状态的对象,以及初始引发时间和表示回调调用之间的时间段的时间。若要取消挂起的计时器,请调用 Timer.Dispose 函数。

有两个其他计时器类。System.Windows.Forms.Timer

类是使用可视化设计器的控件,旨在用于用户界面上下文中;它对用户界面线程引发事件。System.Timers.Timer 类派生自 Component ,所以它可与可视化设计器一同使用;它还引发事件,但对 ThreadPool

线程引发这些事件。System.Threading.Timer 类对 ThreadPool

线程进行回调,并且根本不使用事件模型。它还为回调方法提供状态对象,而其他计时器则不提供。它是极度轻量级的。 监视器

Monitor 对象通过使用 Monitor.Enter 、Monitor.TryEnter 和 Monitor.Exit

方法对特定对象获取锁和释放锁来公开同步访问代码区域的能力。在对代码区域获取锁后,就可以使用

Monitor.Wait、Monitor.Pulse和Monitor.PulseAll方法了。如果锁被暂挂,则Wait

释放该锁并等待通知。当Wait接到通知后,它将返回并再次获取该锁。Pulse和PulseAll

都会发出信号以便等待队列中的下一个线程继续执行。

Monitor将锁定对象(即引用类型),而非值类型。尽管可以向Enter和Exit

传递值类型,但对于每次调用它都是分别装箱的。因为每次调用都创建一个独立的对象,所以Enter

永远不会阻止,而且它要保护的代码并没有真正同步。另外,传递给Exit的对象不同于传递给Enter

的对象,所以Monitor引发

SynchronizationLockException,并显示以下消息:“从不同步的代码块中调用了对象同步方法”

注意到Monitor和WaitHandle对象在使用上的区别是非常重要的。Monitor

对象是完全托管、完全可移植的,并且在操作系统资源要求方面可能更为有效。WaitHandle

对象表示操作系统可等待对象,对于在托管和非托管代码之间进行同步非常有用,并公开一些高级操作系统功能(如同时等待许多对象的能力)。

等待句柄

WaitHandle 类封装 Win32

同步句柄,并用于表示运行库中所有允许执行多个等待操作的同步对象。有关等待句柄与其他同步对象的比较,请参见同步基元概述。

WaitHandle 类本身是抽象类。除派生类之外,它还具有许多对多个事件启用等待的静态方法。从 WaitHandle

派生的类包括:

?Mutex 类。请参见Mutex。

?EventWaitHandle 类及其派生类、AutoResetEvent 和 ManualResetEvent。EventWaitHandle 类是.NET Framework 2.0 版中的新类。请参见EventWaitHandle、AutoResetEvent 和

ManualResetEvent。

?Semaphore 类是 .NET Framework 2.0 版中的新类。请参见信号量。

由于 WaitHandle 类派生自 MarshalByRefObject,所以这些类可用于跨应用程序域边界同步线程的活动。

线程可以通过调用实例方法 WaitOne 在单个等待句柄上阻塞。此外,WaitHandle

类重载了静态方法,以等待所有指定的等待句柄集都已收到信号 (WaitAll),或等待某一指定的等待句柄集收到信号(WaitAny)。这些方法的重载提供了放弃等待的超时间隔、在进入等待之前退出同步上下文的机会,并允许其他线程使用同步上下文。

在 .NET Framework 2.0 版中,等待句柄也具有静态 SignalAndWait

方法,该方法允许线程发送一个等待句柄信号,然后立即等待另一个等待句柄,如同原子操作一样。

WaitHandle 的派生类具有不同的线程关联。事件等待句柄(EventWaitHandle、AutoResetEvent 和ManualResetEvent)以及信号量没有线程关联。任何线程都可以发送事件等待句柄或信号量的信号。另一方面,mutex 没有线程关联。拥有 mutex 的线程必须将其释放;如果线程在它不拥有的 mutex 上调用 ReleaseMutex 方法,则将引发异常。

Mutex

可以使用 Mutex 对象提供对资源的独占访问。Mutex 类比 Monitor

类使用更多系统资源,但是它可以跨应用程序域边界进行封送处理,可用于多个等待,并且可用于同步不同进程中的线程。有关托管同步机制的比较,请参见同步基元概述。

互锁操作

Interlocked

类提供这样一些方法,即同步对多个线程共享的变量的访问的方法。如果该变量位于共享内存中,则不同进程的线程就可以使用该机制。互锁操作是原子的,即整个操作是不能由相同变量上的另一个互锁操作所中断的单元。这在抢先多线程操作系统中是很重要的,在这样的操作系统中,线程可以在从某个内存地址加载值之后但是在有机会更改和存储该值之前被挂起。

Interlocked 类提供了以下操作:

?

在 .NET Framework 2.0 版中,Add 方法向变量添加一个整数值并返回该变量的新值。 ?

在 .NET Framework 2.0 版中,Read 方法作为一个原子操作读取一个 64 位整数值。这在 32 位操作系统上是有用的,在 32 位操作系统上,读取一个 64 位整数通常不是一个原子操作。 ?

Increment 和 Decrement 方法递增或递减某个变量并返回结果值。 ?

Exchange 方法执行指定的变量中的值的原子交换,返回该值并将其替换为新值。在 .NET Framework 2.0 版中,可以使用此方法的一个泛型重载在任何引用类型的变量上执行此交换。请参见 Exchange(T)(T, T)。 ? CompareExchange 方法也交换两个值,但是视比较的结果而定。在 .NET Framework 2.0

版中,可以使用此方法的一个泛型重载在任何引用类型的变量上执行此交换。请参见

CompareExchange(T)(T, T, T)。

在现代处理器中,Interlocked

类的方法经常可以由单个指令来实现。因此,它们提供性能非常高的同步,并且可用于构建更高级的同步机制,例如自旋锁。

有关结合使用 Monitor 和 Interlocked 类的示例,请参见 监视器。

读取器/编写器锁

ReaderWriterLockSlim 类允许多个线程同时读取一个资源,但在向该资源写入时要求线程等待以获得独占锁。 可以在应用程序中使用

ReaderWriterLockSlim ,以便在访问一个共享资源的线程之间提供协调同步。获得的锁是针对

ReaderWriterLockSlim 本身的。

与任何线程同步机制相同,您必须确保任何线程都不会跳过 ReaderWriterLockSlim

提供的锁定。确保做到这一点的一种方法是设计一个封装该共享资源的类。此类将提供访问专用共享资源以及使用专用 ReaderWriterLockSlim 进行同步的成员。有关示例,请参见 ReaderWriterLockSlim

类的代码示例。ReaderWriterLockSlim 足够有效,可用于同步各个对象。

设计您应用程序的结构,让读取和写入操作的时间尽可能最短。因为写入锁是排他的,所以长时间的写入操作会直接影响吞吐量。长时间的读取操作会阻止处于等待状态的编写器,并且,如果至少有一个线程在等待写入访问,则请求读取访问的线程也将被阻止。 注意注意:: .NET Framework 有两个读取器-编写器锁,即 ReaderWriterLockSlim 和

ReaderWriterLock 。建议在所有新的开发工作中使用 ReaderWriterLockSlim 。ReaderWriterLockSlim 类似于 ReaderWriterLock ,只是简化了递归及升级和降级锁定状态的规则。ReaderWriterLockSlim

可避免多种潜在的死锁情况。此外,ReaderWriterLockSlim 的性能明显优于 ReaderWriterLock 。

信号量

Semaphore 类表示一个命名信号量(系统范围)或本地信号量。Windows

信号量是计数信号量,可用于控制对资源池的访问。

同步基元概述

.NET Framework

提供了一系列同步基元来控制线程交互并避免争用条件。这可大致分为三个类别:锁定、通知和联锁操作。

上述类别的定义并非是绝对的:有些同步机制具有多个类别的特征;一次释放一个线程的事件的功能类似于锁定;任何锁定的释放都可看作一个信号;而联锁操作可用于构造锁定。但是,这些类别仍然是有用的。

记住线程同步是协作这一点非常重要。只要有一个线程避开同步机制直接访问受保护的资源,该同步机制就不是有效的。

锁定

锁向一个线程一次提供一个资源的控制功能,或者向指定数目的线程提供此功能。请求正在使用中的独占锁的线程会被阻止,直到该锁变为可用为止。

独占独占锁锁

锁定的最简单的形式是 C# 的 lock 语句(在 Visual Basic 中为

SyncLock ),该语句可控制对代码块的访问。这种块通常称为临界区。lock 语句使通过使用 Monitor 类的 Enter 和 Exit 方法实现的,它使用 try?catch?finally 确保该锁被释放。

通常情况下,使用 lock 语句保护小代码块并且不跨越多个方法是使用 Monitor 类的最佳方法。Monitor 类功能强大,但是容易形成孤立锁和死锁。

Monitor 类

Monitor 类提供了附加功能,可结合 lock 语句使用:

?

TryEnter 方法允许当前被阻止,正在等待资源的线程在指定时间间隔之后放弃。它返回一个指示成功或失败的布尔值,可用于检测和避免潜在的死锁。 ?

Wait 方法由临界区中的线程调用。它放弃对资源的控制并阻止,直到该资源重新可用为止。 ? Pulse 和 PulseAll 方法允许要释放锁或调用 Wait

的线程将一个或多个线程放入就绪队列,以使它们能够获取锁。

Wait 方法重载的

通知

等待另一个线程的信号的最简单方法是调用 Join 方法,该方法会一直阻止,直到另一个线程完成为止。Join 有两个重载方法,这两个方法允许阻止的线程在等待指定时间间隔之后跳出等待。

等待句柄提供了更为丰富的等待和通知功能。

等待句等待句柄柄

等待句柄派生自 WaitHandle 类,后者又派生自

MarshalByRefObject 。因此,等待句柄可用于跨应用程序域边界同步线程的活动。

通过调用实例方法 WaitOne 或者静态方法 WaitAll 、WaitAny 或 SignalAndWait

中的一个方法,线程可由等待句柄阻止。它们的释放方式取决于调用的方法以及等待句柄的种类。

有关概念性概述,请参见 等待句柄。

事件等待句事件等待句柄柄

事件等待句柄包括 EventWaitHandle 类及其派生类 AutoResetEvent 和 ManualResetEvent 。当通过调用 Set 方法或使用 SignalAndWait 方法通知事件等待句柄时,线程会从事件等待句柄释放。

事件等待句柄要么自动重置自身(类似于每次得到通知时只允许一个线程通过的旋转门),要么必须手动重置(类似于在通知前一直关闭,有人将其关闭前则一直打开的大门)。顾名思义,AutoResetEvent 和

ManualResetEvent 分别表示前者和后者。

EventWaitHandle 可表示这两种类型的事件,并且既可以是局部的也可以是全局的。派生类 AutoResetEvent 和 ManualResetEvent 始终是局部的。

事件等待句柄不具有线程关联。任何线程都可以通知事件等待句柄。

有关概念性概述,请参见 EventWaitHandle 、AutoResetEvent 和 ManualResetEvent 。

Mutex 和 Semaphore 类

因为 Mutex 和 Semaphore 类派生自 WaitHandle ,所以它们可用于 WaitHandle

的静态方法。例如,线程可以使用 WaitAll 方法等待,直到满足以下三个条件为止:EventWaitHandle 接收到通知,Mutex 已释放,Semaphore 已释放。类似地,线程可以使用 WaitAny

方法等待,直到满足上述所有条件为止。

对于 Mutex 或 Semaphore ,接收到通知即意味着被释放。如果上述两个类型之一用作 SignalAndWait 方法的第一个参数,该类型即被释放。对于具有线程关联的 Mutex ,如果进行调用的线程不具有该

mutex ,则会引发异常。如前所述,信号量不具有线程关联。

联锁操联锁操作作

联锁操作是由 Interlocked

类的静态方法对某个内存位置执行的简单原子操作。这些原子操作包括添加、递增和递减、交换、依赖于比较的条件交换,以及 32 位平台上的 64 位值的读取操作。 注意注意::

原子性的保证仅限于单个操作;如果必须将多个操作作为一个单元执行,则必须使用更粗粒度的同步机制。 尽管这些操作中没有一个是锁或信号,但它们可用于构造锁和信号。因为它们是 Windows

操作系统固有的,因此联锁操作的执行速度非常快。

联锁操作可用于可变内存保证,以编写展示功能强大的非阻止并发的应用程序,但是,它们需要复杂的低级别编程,因此大多数情况下简单锁是更好的选择。

有关概念性概述,请参见 互锁操作。

解决多线程中11个常见问题

并发危险 解决多线程代码中的11 个常见的问题 Joe Duffy 本文将介绍以下内容:?基本并发概念 ?并发问题和抑制措施 ?实现安全性的模式?横切概念本文使用了以下技术: 多线程、.NET Framework 目录 数据争用 忘记同步 粒度错误 读写撕裂 无锁定重新排序 重新进入 死锁 锁保护 戳记 两步舞曲 优先级反转 实现安全性的模式 不变性 纯度 隔离 并发现象无处不在。服务器端程序长久以来都必须负责处理基本并发编程模型,而随着多核处理器的日益普及,客户端程序也将需要执行一些任务。随着并发操作的不断增加,有关确保安全的问题也浮现出来。也就是说,在面对大量逻辑并发操作和不断变化的物理硬件并行性程度时,程序必须继续保持同样级别的稳定性和可靠性。 与对应的顺序代码相比,正确设计的并发代码还必须遵循一些额外的规则。对内存的读写以及对共享资源的访问必须使用同步机制进行管制,以防发生冲突。另外,通常有必要对线程进行协调以协同完成某项工作。 这些附加要求所产生的直接结果是,可以从根本上确保线程始终保持一致并且保证其顺利向前推进。同步和协调对时间的依赖性很强,这就导致了它们具有不确定性,难于进行预测和测试。 这些属性之所以让人觉得有些困难,只是因为人们的思路还未转变过来。没有可供学习的专门API,也没有可进行复制和粘贴的代码段。实际上的确有一组基础概念需要您学习和适应。很可能随着时间的推移某些语言和库会隐藏一些概念,但如果您现在就开始执行并发操作,则不会遇到这种情况。本

文将介绍需要注意的一些较为常见的挑战,并针对您在软件中如何运用它们给出一些建议。 首先我将讨论在并发程序中经常会出错的一类问题。我把它们称为“安全隐患”,因为它们很容易发现并且后果通常比较严重。这些危险会导致您的程序因崩溃或内存问题而中断。 当从多个线程并发访问数据时会发生数据争用(或竞争条件)。特别是,在一个或多个线程写入一段数据的同时,如果有一个或多个线程也在读取这段数据,则会发生这种情况。之所以会出现这种问题,是因为Windows 程序(如C++ 和Microsoft .NET Framework 之类的程序)基本上都基于共享内存概念,进程中的所有线程均可访问驻留在同一虚拟地址空间中的数据。静态变量和堆分配可用于共享。请考虑下面这个典型的例子: static class Counter { internal static int s_curr = 0; internal static int GetNext() { return s_curr++; } } Counter 的目标可能是想为GetNext 的每个调用分发一个新的唯一数字。但是,如果程序中的两个线程同时调用GetNext,则这两个线程可能被赋予相同的数字。原因是s_curr++ 编译包括三个独立的步骤: 1.将当前值从共享的s_curr 变量读入处理器寄存器。 2.递增该寄存器。 3.将寄存器值重新写入共享s_curr 变量。 按照这种顺序执行的两个线程可能会在本地从s_curr 读取了相同的值(比如42)并将其递增到某个值(比如43),然后发布相同的结果值。这样一来,GetNext 将为这两个线程返回相同的数字,导致算法中断。虽然简单语句s_curr++ 看似不可分割,但实际却并非如此。 忘记同步 这是最简单的一种数据争用情况:同步被完全遗忘。这种争用很少有良性的情况,也就是说虽然它们是正确的,但大部分都是因为这种正确性的根基存在问题。 这种问题通常不是很明显。例如,某个对象可能是某个大型复杂对象图表的一部分,而该图表恰好可使用静态变量访问,或在创建新线程或将工作排入线程池时通过将某个对象作为闭包的一部分进行传递可变为共享图表。 当对象(图表)从私有变为共享时,一定要多加注意。这称为发布,在后面的隔离上下文中会对此加以讨论。反之称为私有化,即对象(图表)再次从共享变为私有。 对这种问题的解决方案是添加正确的同步。在计数器示例中,我可以使用简单的联锁: static class Counter { internal static volatile int s_curr = 0; internal static int GetNext() { return Interlocked.Increment(ref s_curr);

进程与线程的区别 进程的通信方式 线程的通信方式

进程与线程的区别进程的通信方式线 程的通信方式 进程与线程的区别进程的通信方式线程的通信方式2011-03-15 01:04 进程与线程的区别: 通俗的解释 一个系统运行着很多进程,可以比喻为一条马路上有很多马车 不同的进程可以理解为不同的马车 而同一辆马车可以有很多匹马来拉--这些马就是线程 假设道路的宽度恰好可以通过一辆马车 道路可以认为是临界资源 那么马车成为分配资源的最小单位(进程) 而同一个马车被很多匹马驱动(线程)--即最小的运行单位 每辆马车马匹数=1 所以马匹数=1的时候进程和线程没有严格界限,只存在一个概念上的区分度 马匹数1的时候才可以严格区分进程和线程 专业的解释: 简而言之,一个程序至少有一个进程,一个进程至少有一个线程.

线程的划分尺度小于进程,使得多线程程序的并发性高。另外,进程在执 行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序 的运行效率。 线程在执行过程中与进程还是有区别的。每个独立的线程有一个程序运行 的入口、顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在 应用程序中,由应用程序提供多个线程执行控制。 从逻辑角度来看,多线程的意义在于一个应用程序中,有多个执行部分可 以同时执行。但操作系统并没有将多个线程看做多个独立的应用,来实现进程 的调度和管理以及资源分配。这就是进程和线程的重要区别。 进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位. 线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的 能独立运行的基本单位.线程自己基本上不拥有系统资源,只拥有一点在运行中 必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的 其他的线程共享进程所拥有的全部资源. 一个线程可以创建和撤销另一个线程;同一个进程中的多个线程之间可以 并发执行 进程和线程的主要差别在于它们是不同的操作系统资源管理方式。进程有 独立的地址空间,一个进程崩溃后,在保护模式下不会对其它进程产生影响, 而线程只是一个进程中的不同执行路径。线程有自己的堆栈和局部变量,但线 程之间没有单独的地址空间,一个线程死掉就等于整个进程死掉,所以多进程 的程序要比多线程的程序健壮,但在进程切换时,耗费资源较大,效率要差一些。但对于一些要求同时进行并且又要共享某些变量的并发操作,只能用线程,不能用进程。如果有兴趣深入的话,我建议你们看看《现代操作系统》或者 《操作系统的设计与实现》。对就个问题说得比较清楚。 +++ 进程概念

高速数据采集卡的信号处理功能

高速数据采集卡的信号处理功能 高速数据采集卡的信号处理 高速数据采集卡可以实现精确的,高分辨率的数据采集,并传输到主机上。在高速数据采集卡和主机上的应用信号处理函数,可以对获取信号进行增强处理,或者通过简单测量抽取最有用的信息。 现代高速数据采集卡支持软件,像坤驰科技公司代理的Spectrum的Sbench6 和很多第三方程序,吸收了很多信号处理的功能。这其中包括波形运算,积分,boxcar平均,快速傅里叶变换FFT,前置滤波功能,和直方图。这个应用笔记将研究所有这些功能并且提供这些工具均有应用的典型的范例。 模拟计算(波形运算) 模拟计算包括对获取波形的加法,减法,乘法和除法。在数据上应用这些函数是为了提高信号的质量,或者导出备选函数。举一个例子就是用减法将差分组件和一个差动波形结合产生的共模噪声和收集的减少的值。另一个例子是用电流和电压波形的乘积来计算瞬时功率。 在样品波形上通过样品基础应用每一个算术函数。这是假设连结起来的波形都有相同的记录长度。图表1显示了使用软件为模拟计算所做的相关配置。 在需要的信号源通道上右击会弹出选择框。选择“计算”会打开计算的选择栏,信号计算,信号转换,和信号平均。信号计算的一种选择可提供路径到傅里叶变换,直方图,滤波和其它的一些功能。如果选择模拟计算,计算对话框就会弹出以允许对所需要的运算算法进行设置。在这个例子中,两个输入信号被相加。其他的一些选项如减法,加法和除法。类似的选择路径能够引出其他的一些可讨论的信号处理函数。

第一个应用波形算法解决实际问题的例子就是从另一个信号里面减掉另一个信号成分来估计差分信号。如图标2所示。 差分信号通常被用来提高信号的完整性。表2中例子里一个1MHZ的时钟信号中“P”和“N”成分(在右手边面板里显示的)是用减法来运算结合起来的。所产生的差分信号在左边网格里显示。左侧中心的信息面板用参数来测量峰峰值和每种波形的平均值。要注意差分信号有两倍的峰峰值幅度和一个接近零的平均值。也要注意到差分信号成分里的共模噪声已经被消除了。

多线程练习题目

多线程练习题目

————————————————————————————————作者:————————————————————————————————日期:

多线程? 一、单项 1.下述哪个选项为真?() A.Error类是一个RoutimeException异常 B.任何抛出一个RoutimeException异常的语句必须包含在try块之内 C.任何抛出一个Error对象的语句必须包含在try块之内 D.任何抛出一个Exception异常的语句必须包含在try块之内 2.下列关于Java线程的说法哪些是正确的?( ) A.每一个Java线程可以看成由代码、一个真实的CPU以及数据3部分组成 B.创建线程的两种方法,从Thread类中继承的创建方式可以防止出现多父类问题 C.Thread类属于java.util程序包 D.以上说法无一正确 3.哪个关键字可以对对象加互斥锁?( ) A.transient B.synchronized C.serialize D.static 4.下列哪个方法可用于创建一个可运行的类?() A.public classXimplements Runable{ publicvoid run() {……}} B.public class XimplementsThread { public void run(){……} } C. public class X implements Thread { public int run() {……} } D.publicclass X implements Runable { protectedvoidrun(){……}} 5.下面哪个选项不会直接引起线程停止执行?( ) A.从一个同步语句块中退出来 B.调用一个对象的wait方法 C.调用一个输入流对象的read方法 D.调用一个线程对象的setPriority方法 6.使当前线程进入阻塞状态,直到被唤醒的方法是() A.resume()方法 B.wait()方法 C.suspend()方法D.notify()方法 7.运行下列程序,会产生的结果是( ) publicclassXextends Thread implements Runnable { public void run(){ System.out.println(“this is run()”); } publicstaticvoid main(String[] args) { Thread t=new Thread(newX()); t.start();

JAVA多线程试题 答案

多线程 一.选择题 1.下列说法中错误的一项是(A) A.线程就是程序 B.线程是一个程序的单个执行流 B.多线程是指一个程序的多个执行流D.多线程用于实现并发 2.下列哪个一个操作不能使线程从等待阻塞状态进入对象阻塞状态(D) A.等待阴塞状态下的线程被notify()唤 B.等待阻塞状态下的纯种被interrput()中断 C.等待时间到 D.等待阻塞状态下的线程调用wait()方法 3.下列哪个方法可以使线程从运行状态进入其他阻塞状态(A) A.sleep B.wait C.yield D.start 4.下列说法中错误的一项是(D) A.一个线程是一个Thread类的实例 B.线程从传递给纯种的Runnable实例run()方法开始执行 C.线程操作的数据来自Runnable实例 D.新建的线程调用start()方法就能立即进入运行状态 5.下列关于Thread类提供的线程控制方法的说法中,错误的一项是(D) A.在线程A中执行线程B的join()方法,则线程A等待直到B执行完成 B.线程A通过调用interrupt()方法来中断其阻塞状态 C.若线程A调用方法isAlive()返回值为true,则说明A正在执行中 D.currentThread()方法返回当前线程的引用 6.下列说法中,错误的一项是() A.对象锁在synchronized()语句执行完之后由持有它的线程返还 B.对象锁在synchronized()语句中出现异常时由持有它的线程返还 C.当持有锁的线程调用了该对象的wait()方法时,线程将释放其持有的锁 D.当持有锁的线程调用了该对象的构造方法时,线程将释放其持有的锁 7.下面的哪一个关键字通常用来对对象的加锁,从而使得对对象的访问是排他的A A.sirialize B transient C synchronized D static 二.填空题 1.在操作系统中,被称做轻型的进程是线程 2.多线程程序设计的含义是可以将一个程序任务分成几个并行的任务 3.在Java程序中,run()方法的实现有两种方式:实现Runnable接口和继承Thread类 4.多个线程并发执行时,各个线程中语句的执行顺序是确定的,但是线程之间的相对执行顺序是不确定的 6.Java中的对象锁是一种独占的排他锁 7.程序中可能出现一种情况:多个线种互相等待对方持有的锁,而在得到对方的锁之前都不会释放自己的锁,这就是死锁 8.线程的优先级是在Thread类的常数MIN_PRIORITY和MAX_PRIORITY 之间的一个值 9.处于新建状态的线程可以使用的控制方法是start()和stop()。 10.一个进程可以包含多个线程

多线程练习题目

多线程 一、单项 1.下述哪个选项为真?( ) A.Error类是一个RoutimeException异常 B.任何抛出一个RoutimeException异常的语句必须包含在try块之内 C.任何抛出一个Error对象的语句必须包含在try块之内 D. 任何抛出一个Exception异常的语句必须包含在try块之内 2.下列关于Java线程的说法哪些是正确的?( ) A.每一个Java线程可以看成由代码、一个真实的CPU以及数据3部分组成 B.创建线程的两种方法,从Thread类中继承的创建方式可以防止出现多父类问题 C.Thread类属于java.util程序包 D.以上说法无一正确 3.哪个关键字可以对对象加互斥锁?( ) A.transient B.synchronized C.serialize D.static 4.下列哪个方法可用于创建一个可运行的类?() A.public class X implements Runable { public void run() {……} } B. public class X implements Thread { public void run() {……} } C. public class X implements Thread { public int run() {……} } D.public class X implements Runable { protected void run() {……} } 5.下面哪个选项不会直接引起线程停止执行?( ) A.从一个同步语句块中退出来 B.调用一个对象的wait方法 C.调用一个输入流对象的read方法 D.调用一个线程对象的setPriority方法 6.使当前线程进入阻塞状态,直到被唤醒的方法是( ) A.resume()方法 B.wait()方法 C.suspend()方法 D.notify()方法 7.运行下列程序,会产生的结果是( ) public class X extends Thread implements Runnable { public void run(){ System.out.println(“this is run()”); } public static void main(String[] args) { Thread t=new Thread(new X()); t.start(); } }

超高速数据采集技术发展现状

2003年第17卷第4期测试技术学报V o l.17 N o.4 2003 (总第46期)JOURNAL OF TEST AND M EASURE M ENT TECHNOLOG Y(Sum N o.46) 文章编号:167127449(2003)0420287206 超高速数据采集技术发展现状 Ξ马海潮 (辽宁省葫芦岛市92941部队,辽宁葫芦岛市125001) 摘 要: 介绍超高速数据采集技术发展现状和动态.概述当前领先的几种超高速数据采集板卡;给出了目 前主要超高速ADC芯片,对超高速ADC芯片静动态性能指标进行了描述. 关键词: 超高速数据采集系统;闪式ADC;标准总线 中图分类号: T P274 文献标识码:A Extra H igh Speed Data Acquisition Technology D evelop m en ts M A H ai2chao (N o.92941PLA,L iaoning P rovince,H uludao125001,Ch ina) Abstract: T he cu rren t ex tra h igh speed data acqu isiti on techno logy developm en ts are summ arized. Several leading ex tra h igh sp eed data acqu isiti on boards in m arket are given.M ain p roducts of ex tra h igh speed flash ADC ch i p s are p resen ted.T he static and dynam ic characteristics of an ex tra h igh speed ADC ch i p are described. Key words:h igh2sp eed data acqu isiti on system;flash ADC;standard bu s 将模拟信号转换为数字信号、并进行存储和计算机处理显示的过程称为数据采集,而相应的系统则为数据采集系统(D ata A cqu isiti on System)[1~3].数据采集技术是信息科学的一个重要分支,它研究信息数据的采集、存储、处理及控制等工作,它与传感器技术、信号处理技术、计算机技术一起构成了现代检测技术的基础. 由于数据采集技术可以使许多抽象的模拟量数字化,进而给出其量值,或通过信号处理对该模拟量进行分析.与模拟系统相比,数字系统具有精度高、可靠性高等优点,因此,数据采集技术的应用越来越广泛.如温度、压力、位置、流量等模拟量,可以通过不同类型的传感器将其转换为电信号模拟量(如电压、电流或电脉冲等),再通过适当的信号调理将信号送给模拟数字转换器(ADC),使其转换为可以进一步处理的数字信号送给数字信号处理器或微处理机.反之,数字信号处理器或微处理机可通过数字模拟转换器(DA C)将其产生的数字信号转换为模拟信号,再通过信号调理进行输出. 随着科学技术的发展和数据采集技术的广泛应用,对数据采集系统的许多技术指标,如采样率、分辨率、存储深度、数字信号处理速度、抗干扰能力等方面提出了越来越高的要求,其中前两项为评价超高速数据采集系统的最重要技术指标. 提高数据采集系统的采样率可更深入、更细微、更精确地了解物理量变化特性.在许多应用场合,需要超高速数据采集系统来完成许多低速数据采集系统无法完成的工作.在雷达制导方面,需超高速、高精度地大量获取目标数据,并进行实时处理以完成对运动目标的检测和识别.在观测供电传输线上的浪涌电流时,由于浪涌的持续时间仅有几百纳秒,而电压的变化范围则可达几千伏,要精确地了解其变化 Ξ收稿日期:2003205219  作者简介:马海潮(1962-),男,博士,副总工程师,主要从事测控总体和调整数字信号处理系统硬件和软件设计等研究.

15个Java多线程面试题及答案

15个Java多线程面试题及答案 1)现在有T1、T2、T3三个线程,你怎样保证T2在T1执行完后执行,T3在T2执行完后执行? 这个线程问题通常会在第一轮或电话面试阶段被问到,目的是检测你对”join”方法是否熟悉。这个多线程问题比较简单,可以用join方法实现。 2)在Java中Lock接口比synchronized块的优势是什么?你需要实现一个高效的缓存,它允许多个用户读,但只允许一个用户写,以此来保持它的完整性,你会怎样去实现它? lock接口在多线程和并发编程中最大的优势是它们为读和写分别提 供了锁,它能满足你写像ConcurrentHashMap这样的高性能数据结构和有条件的阻塞。Java线程面试的问题越来越会根据面试者的回答来提问。芯学苑老师强烈建议在你在面试之前认真读一下Locks,因为当前其大量用于构建电子交易终统的客户端缓存和交易连接空间。 3)在java中wait和sleep方法的不同?

通常会在电话面试中经常被问到的Java线程面试问题。最大的不同是在等待时wait会释放锁,而sleep一直持有锁。Wait通常被用于线程间交互,sleep通常被用于暂停执行。 4)用Java实现阻塞队列。 这是一个相对艰难的多线程面试问题,它能达到很多的目的。第一,它可以检测侯选者是否能实际的用Java线程写程序;第二,可以检测侯选者对并发场景的理解,并且你可以根据这个问很多问题。如果他用wait()和notify()方法来实现阻塞队列,你可以要求他用最新的Java 5中的并发类来再写一次。 5)用Java写代码来解决生产者——消费者问题。 与上面的问题很类似,但这个问题更经典,有些时候面试都会问下面的问题。在Java中怎么解决生产者——消费者问题,当然有很多解决方法,我已经分享了一种用阻塞队列实现的方法。有些时候他们甚至会问怎么实现哲学家进餐问题。 6)用Java编程一个会导致死锁的程序,你将怎么解决?

精选大厂java多线程面试题50题

Java多线程50题 1)什么是线程? 线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位。程序员可以通过它进行多处理器编程,你可以使用多线程对运算密集型任务提速。比如,如果一个线程完成一个任务要100毫秒,那么用十个线程完成改任务只需10毫秒。 2)线程和进程有什么区别? 线程是进程的子集,一个进程可以有很多线程,每条线程并行执行不同的任务。不同的进程使用不同的内存空间,而所有的线程共享一片相同的内存空间。别把它和栈内存搞混,每个线程都拥有单独的栈内存用来存储本地数据。更多详细信息请点击这里。 3)如何在Java中实现线程? https://www.doczj.com/doc/1c3084660.html,ng.Thread类的实例就是一个线程但是它需要调用https://www.doczj.com/doc/1c3084660.html,ng.Runnable接口来执行,由于线程类本身就是调用的 Runnable接口所以你可以继承https://www.doczj.com/doc/1c3084660.html,ng.Thread类或者直接调用Runnable接口来重写run()方法实现线程。 4)Thread类中的start()和run()方法有什么区别? 这个问题经常被问到,但还是能从此区分出面试者对Java线程模型的理解程度。start()方法被用来启动新创建的线程,而且start()内部调用了run()方法,这和直接调用run()方法的效果不一样。当你

调用run()方法的时候,只会是在原来的线程中调用,没有新的线程启动,start()方法才会启动新线程。 5)Java中Runnable和Callable有什么不同? Runnable和Callable都代表那些要在不同的线程中执行的任务。Runnable从JDK1.0开始就有了,Callable是在JDK1.5增加的。它们的主要区别是Callable的call()方法可以返回值和抛出异常,而Runnable的run()方法没有这些功能。Callable可以返回装载有计算结果的Future对象。 6)Java内存模型是什么? Java内存模型规定和指引Java程序在不同的内存架构、CPU 和操作系统间有确定性地行为。它在多线程的情况下尤其重要。 Java内存模型对一个线程所做的变动能被其它线程可见提供了保证,它们之间是先行发生关系。 ●线程内的代码能够按先后顺序执行,这被称为程序次序 规则。 ●对于同一个锁,一个解锁操作一定要发生在时间上后发 生的另一个锁定操作之前,也叫做管程锁定规则。 ●前一个对Volatile的写操作在后一个volatile的读操作之 前,也叫volatile变量规则。 ●一个线程内的任何操作必需在这个线程的start()调用之 后,也叫作线程启动规则。 ●一个线程的所有操作都会在线程终止之前,线程终止规

多线程编程的详细说明完整版

VB .NET多线程编程的详细说明 作者:陶刚整理:https://www.doczj.com/doc/1c3084660.html, 更新时间:2011-4-1 介绍 传统的Visual Basic开发人员已经建立了同步应用程序,在这些程序中事务按顺序执行。尽管由于多个事务多多少少地同时运行使多线程应用程序效率更高,但是使用先前版本的Visual Basic很难建立这类程序。 多线程程序是可行的,因为操作系统是多任务的,它有模拟同一时刻运行多个应用程序的能力。尽管多数个人计算机只有一个处理器,但是现在的操作系统还是通过在多个执行代码片断之间划分处理器时间提供了多任务。线程可能是整个应用程序,但通常是应用程序可以单独运行的一个部分。操作系统根据线程的优先级和离最近运行的时间长短给每一个线程分配处理时间。多线程对于时间密集型事务(例如文件输入输出)应用程序的性能有很大的提高。 但是也有必须细心的地方。尽管多线程能提高性能,但是每个线程还是需要用附加的内存来建立和处理器时间来运行,建立太多的线程可能降低应用程序的性能。当设计多线程应用程序时,应该比较性能与开销。 多任务成为操作系统的一部分已经很久了。但是直到最近Visual Basic程序员才能使用无文档记录特性(undocumented)或者间接使用COM组件或者操作系统的异步部分执行多线程事务。.NET框架组件为开发多线程应用程序,在System.Threading名字空间中提供了全面的支持。 本文讨论多线程的好处以及怎样使用Visual Basic .NET开发多线程应用程序。尽管Visual Basic .NET和.NET框架组件使开发多线程应用程序更容易,但是本文作了调整使其适合高级读者和希望从早期Visual Basic转移到Visual Basic .NET的开发人员。 多线程处理的优点 尽管同步应用程序易于开发,但是它们的性能通常比多线程应用程序低,因为一个新的事务必须等待前面的事务完成后才能开始。如果完成某个同步事务的时间比预想的要长,应用程序可能没有响应。多线程处理可以同时运行多个过程。例如,字处理程序能够在继续操作文档的同时执行拼写检查事务。因为多线程应用程序把程序分解为独立的事务,它们能通过下面的途径充分提高性能: l 多线程技术可以使程序更容易响应,因为在其它工作继续时用户界面可以保持激活。 l 当前不忙的事务可以把处理器时间让给其它事务。 l 花费大量处理时间的事务可以周期性的把时间让给其它的事务。 l 事务可以在任何时候停止。 l 可以通过把单独事务的优先级调高或调低来优化性能。 明确地建立多线程应用程序的决定依赖于几个因素。多线程最适合下面的情况:

Java第七单元练习题-Java多线程机制

7Java多线程机制 7.1单项选择题 1. 线程调用了sleep()方法后,该线程将进入()状态。 A. 可运行状态 B. 运行状态 C. 阻塞状态 D. 终止状态 2. 关于java线程,下面说法错误的是() A. 线程是以CPU为主体的行为 B. java利用线程使整个系统成为异步 C. 创建线程的方法有两种:实现Runnable接口和继承Thread类 D. 新线程一旦被创建,它将自动开始运行 3. 在java中的线程模型包含() A. 一个虚拟处理器 B. CPU执行的代码 C. 代码操作的数据 D. 以上都是 4.在java语言中,临界区可以是一个语句块,或者是一个方法,并用()关键字标识。 A. synchronized B. include C. import D. Thread 5. 线程控制方法中,yield()的作用是() A. 返回当前线程的引用 B. 使比其低的优先级线程执行 C. 强行终止线程 D. 只让给同优先级线程运行 6. 线程同步中,对象的锁在()情况下持有线程返回 A. 当synchronized()语句块执行完后 B. 当在synchronized()语句块执行中出现例外(exception)时 C. 当持有锁的线程调用该对象的wait()方法时 D. 以上都是 7. 在以下()情况下,线程就进入可运行状态 A. 线程调用了sleep()方法时 B. 线程调用了join()方法时

C. 线程调用了yield()方法时 D. 以上都是 8. java用()机制实现了进程之间的异步执行 A. 监视器 B. 虚拟机 C. 多个CPU D. 异步调用 类的方法中,toString()方法的作用是() A. 只返回线程的名称 B. 返回当前线程所属的线程组的名称 C. 返回当前线程对象 D. 返回线程的名称 语言具有许多优点和特点,下列选项中,哪个反映了Java程序并行机制的特点() A. 安全性 B. 多线程 C. 跨平台 D. 可移值 11.以下哪个关键字可以用来对对象加互斥锁?() A. transient B. synchronized C. serialize D. static 12.下面关于进程、线程的说法不正确的是( )。 A.进程是程序的一次动态执行过程。一个进程在其执行过程中,可以产生多个线程——多线程,形成多条执行线索。 B.线程是比进程更小的执行单位,是在一个进程中独立的控制流,即程序内部的控制流。线程本身不能自动运行,栖身于某个进程之中,由进程启动执行。 C.Java多线程的运行与平台无关。 D.对于单处理器系统,多个线程分时间片获取CPU或其他系统资源来运行。对于多处理器系统,线程可以分配到多个处理器中,从而真正的并发执行多任务。 7.2填空题 1.________是java程序的并发机制,它能同步共享数据、处理不同的事件。 2.线程是程序中的一个执行流,一个执行流是由CPU运行程序的代码、__________所形 成的,因此,线程被认为是以CPU为主体的行为。 3.线程的终止一般可以通过两种方法实现:自然撤销或者是__________. 4.线程模型在java中是由__________类进行定义和描述的。 5.线程的创建有两种方法:实现_________接口和继承Thread类。 6.多线程程序设计的含义是可以将程序任务分成几个________的子任务。 7.按照线程的模型,一个具体的线程也是由虚拟的CPU、代码与数据组成,其中代码与数 据构成了___________,线程的行为由它决定。 8.ava中,新建的线程调用start()方法、如(),将使线程的状态从New(新建状态)转换为 _________。 9.多线程是java程序的________机制,它能同步共享数据,处理不同事件。 10.进程是由代码、数据、内核状态和一组寄存器组成,而线程是表示程序运行状态的

windows 并发的多线程的应用

(1)苹果香蕉问题 #include using namespace std; #include #include int k; HANDLE Apple_;HANDLE Banana_; CRITICAL_SECTION mmutex; DWORD WINAPI Son(LPVOID n) {//HANDLE Apple_; CRITICAL_SECTION mmutex; int i=1; OpenSemaphore(MUTEX_ALL_ACCESS,false,"Apple_"); while(1) { ::WaitForSingleObject(Apple_,INFINITE);//等苹果 cout<<"Son eats"<

数据采集与处理技术试卷讲解

一、绪论 (一)、1、“数据采集”是指什么? 将温度、压力、流量、位移等模拟量经测量转换电路输出电量后再采集转换成数字量后,再由PC 机进行存储、处理、显示或打印的过程。 2、数据采集系统的组成? 由数据输入通道,数据存储与管理,数据处理,数据输出及显示这五个部分组成。 3、数据采集系统性能的好坏的参数? 取决于它的精度和速度。 4、数据采集系统具有的功能是什么? (1)、数据采集,(2)、信号调理,(3)、二次数据计算,(4)、屏幕显示,(5)、数据存储,(6)、打印输出,(7)、人机联系。 5、数据处理系统的分类? 分为预处理和二次处理两种;即为实时(在线)处理和事后(脱机)处理。 6、集散式控制系统的典型的三级结构? 一种是一般的微型计算机数据采集系统,一种是直接数字控制型计算机数据采集系统,还有一种是集散型数据采集系统。 7、控制网络与数据网络的结合的优点? 实现信号的远程传送与异地远程自动控制。 (二)、问答题: 1、数据采集的任务是什么? 数据采集系统的任务:就是传感器输出信号转换为数字信号,送入工业控制机机处理,得出所需的数据。同时显示、储存或打印,以便实现对某些物理量的监视,还将被生产过程中的PC机控制系统用来控制某些物理量。 2、微型计算机数据采集系统的特点是 (1)、系统结构简单;(2)、微型计算机对环境要求不高;(3)、微型计算机的价格低廉,降低了数据采集系统的成本;(4)、微型计算机数据采集系统可作为集散型数据采集系统的一个基本组成部分;(5)、微型计算机的各种I/O模板及软件齐全,易构成系统,便于使用和维修; 3、简述数据采集系统的基本结构形式,并比较其特点? (1)、一般微型计算机数据采集与处理系统是由传感器、模拟多路开关、程控放大器、采样/保持器、A/D转换器、计算机及外设等部分组成。 (2)、直接数字控制型数据采集与处理系统(DDC)是既可对生产过程中的各个参数进行巡回检测,还可根据检测结果,按照一定的算法,计算出执行器应该的状态(继电器的通断、阀门的位置、电机的转速等),完成自动控制的任务。系统的I/O通道除了AI和DI外,还有模拟量输出(AO)通道和开关量输出(FDO)通道。 (3)、集散式控制系统也称为分布式控制系统,总体思想是分散控制,集中管理,即用几台计算机分别控制若干个回路,再用监督控制计算机进行集中管理。 (三)、分析题: 1、如图所示,分析集散型数据采集与处理系统的组成原理,系统有那些特点?

多线程与并发面试题

多线程与并发面试题

JAVA多线程和并发基础面试问答 原文链接译文连接作者:Pankaj 译者:郑旭东校对:方腾飞 多线程和并发问题是Java技术面试中面试官比较喜欢问的问题之一。在这里,从面试的角度列出了大部分重要的问题,可是你依然应该牢固的掌握Java多线程基础知识来对应日后碰到的问题。(校对注:非常赞同这个观点) Java多线程面试问题 1. 进程和线程之间有什么不同? 一个进程是一个独立(self contained)的运行环境,它能够被看作一个程序或者一个应用。而线程是在进程中执行的一个任务。Java运行环境是一个包含了不同的类和程序的单一进程。线程能够被称为轻量级进程。线程需要较少的资源来创立和驻留在进程中,而且能够共享进程中的资源。 2. 多线程编程的好处是什么?

在多线程程序中,多个线程被并发的执行以提高程序的效率,CPU不会因为某个线程需要等待资源而进入空闲状态。多个线程共享堆内存(heap memory),因此创立多个线程去执行一些任务会比创立多个进程更好。举个例子,Servlets比CGI更好,是因为Servlets支持多线程而CGI不支持。 3. 用户线程和守护线程有什么区别? 当我们在Java程序中创立一个线程,它就被称为用户线程。一个守护线程是在后台执行而且不会阻止JVM终止的线程。当没有用户线程在运行的时候,JVM关闭程序而且退出。一个守护线程创立的子线程依然是守护线程。 4. 我们如何创立一个线程? 有两种创立线程的方法:一是实现Runnable接口,然后将它传递给Thread的构造函数,创立一个Thread对象;二是直接继承Thread类。若想了解更多能够阅读这篇关于如何在Java中创立线程的文章。 5. 有哪些不同的线程生命周期?

数据采集与处理技术

数据采集与处理技术 参考书目: 1.数据采集与处理技术马明建周长城西安交通大学出版社 2.数据采集技术沈兰荪中国科学技术大学出版社 3.高速数据采集系统的原理与应用沈兰荪人民邮电出版社 第一章绪论 数据采集技术(Data Acquisition)是信息科学的一个重要分支,它研究信息数据的采集、存贮、处理以及控制等作业。在智能仪器、信号处理以及工业自动控制等领域,都存在着数据的测量与控制问题。将外部世界存在的温度、压力、流量、位移以及角度等模拟量(Analog Signal)转换为数字信号(Digital Signal), 在收集到计算机并进一步予以显示、处理、传输与记录这一过程,即称为“数据采集”。相应的系统即为数据采集系统(Data Acquisition System,简称DAS)数据采集技术以在雷达、通信、水声、遥感、地质勘探、震动工程、无损检测、语声处理、智能仪器、工业自动控制以及生物医学工程等领域有着广泛的应用。 1.1 数据采集的意义和任务 数据采集是指将温度、压力、流量、位移等模拟量采集、转换为数字量后,再由计算机进行存储、处理、显示或打印的过程。相应的系统称为数据采集系统。 数据采集系统的任务:采集传感器输出的模拟信号并转换成计算机能识别的数字信号,然后送入计算机,根据不同的需要由计算机进行相应的计算和处理,得出所需的数据。与此同时,将计算得到的数据进行显示或打印,以便实现对某些物理量的监视,其中一部分数据还将被生产过程中的计算机控制系统用来控制某些物理量。 数据采集系统的好坏,主要取决于精度和速度。 1.2 数据采集系统的基本功能 1.数据采集:采样周期

多线程练习题卷

多线程 一、单项选择题(从下列各题四个备选答案中选出一个正确答案,并将其代号写在答题纸相应位置处。答案错选或未选者,该题不得分。)50 1.下述哪个选项为真?( ) A.Error类是一个RoutimeException异常 B.任何抛出一个RoutimeException异常的语句必须包含在try块之内 C.任何抛出一个Error对象的语句必须包含在try块之内 D. 任何抛出一个Exception异常的语句必须包含在try块之内 2.下列关于Java线程的说法哪些是正确的?( ) A.每一个Java线程可以看成由代码、一个真实的CPU以及数据3部分组成 B.创建线程的两种方法,从Thread类中继承的创建方式可以防止出现多父类问题 C.Thread类属于java.util程序包 D.以上说法无一正确 3.哪个关键字可以对对象加互斥锁?( ) A.transient B.synchronized C.serialize D.static 4.下列哪个方法可用于创建一个可运行的类?() A.public class X implements Runable { public void run() {……} } B. public class X implements Thread { public void run() {……} } C. public class X implements Thread { public int ru n() {……} } D.public class X implements Runable { protected void run() {……} } 5.下面哪个选项不会直接引起线程停止执行?( ) A.从一个同步语句块中退出来 B.调用一个对象的wait方法 C.调用一个输入流对象的read方法 D.调用一个线程对象的setPriority方法 6.使当前线程进入阻塞状态,直到被唤醒的方法是( ) A.resume()方法 B.wait()方法 C.suspend()方法 D.notify()方法 7.运行下列程序,会产生的结果是( ) public class X extends Thread implements Runnable { public void run(){ System.out.println(“this is run()”); } public static void main(String[] args) { Thread t=new Thread(new X()); t.start(); }

经典多线程的练习题

java中有几种方法可以实现一个线程(jdk5.0之前)?用什么关键字修饰同步方法? stop()和suspend()方法为何不推荐使用? 答:有两种实现方法,分别是继承Thread类与实现Runnable接口。 用synchronized关键字修饰同步方法,反对使用stop(),是因为它不安全。它会解除由线程获取的所有锁定,而且如果对象处于一种不连贯状态,那么其他线程能在那种状态下检查和修改它们。结果很难检查出真正的问题所在。 suspend()方法容易发生死锁。调用suspend()的时候,目标线程会停下来,但却仍然持有在这之前获得的锁定。此时,其他任何线程都不能访问锁定的资源,除非被"挂起"的线程恢复运行。对任何线程来说,如果它们想恢复目标线程,同时又试图使用任何一个锁定的资源,就会造成死锁。所以不应该使用suspend(),而应在自己的Thread类中置入一个标志, 指出线程应该活动还是挂起。若标志指出线程应该挂起,便用wait()命其进入等待状态。若标志指出线程应当恢复,则用一个notify()重新启动线程。 sl eep() 和wait() 有什么区别? 答:sleep是线程类(Thread)的方法,导致此线程暂停执行指定时间,给执行机会给其他线程,但是监控状态依然保持,到时后会自动恢复。调用sleep不会释放对象锁。 wait是Object类的方法,对此对象调用wait方法导致本线程放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象发出notify方法(或notifyAll)后本线程才进入对象锁定池准备获得对象锁进入运行状态。 同步和异步有何异同,在什么情况下分别使用他们?举例说明。 答:如果数据将在线程间共享。例如正在写的数据以后可能被另一个线程读到,或者正在读的数据可能已经被另一个线程写过了,那么这些数据就是共享数据,必须进行同步存取。 当应用程序在对象上调用了一个需要花费很长时间来执行的方法,并且不希望让程序等待方法的返回时,就应该使用异步编程,在很多情况下采用异步途径往往更有效率。

相关主题
文本预览
相关文档 最新文档