生命之价
---程序员
posts - 21,  comments - 6,  trackbacks - 0
命名空间:  System.Collections.Generic
程序集:  System(在 System.dll 中)
T

指定队列中元素的类型。

队列在按接收顺序存储消息方面非常有用,以便于进行顺序处理。存储在 Queue<(Of <(T>)>) 中的对象在一端插入,从另一端移除。

Queue<(Of <(T>)>) 的容量是指 Queue<(Of <(T>)>) 可以容纳的元素数。当向 Queue<(Of <(T>)>) 添加元素时,将通过重新分配内部数组,根据需要自动增大容量。可通过调用 TrimExcess 来减少容量。

Queue<(Of <(T>)>) 接受 nullNothingnullptrnull 引用(在 Visual Basic 中为 Nothing 作为引用类型的有效值并且允许有重复的元素。

下面的代码示例演示了 Queue<(Of <(T>)>) 泛型类的几个方法。此代码示例创建一个具有默认容量的字符串队列,并使用 Enqueue 方法对五个字符串进行排队。枚举队列元素,这不会更改队列的状态。使用 Dequeue 方法使第一个字符串出列。使用 Peek 方法查找队列中的下一项,然后使用 Dequeue 方法使该项出列。

使用 ToArray 方法创建一个数组并将队列元素复制到该数组,然后将该数组传递给接受 IEnumerable<(Of <(T>)>)Queue<(Of <(T>)>) 构造函数以创建队列副本。将显示副本的元素。

创建一个大小是队列大小两倍的数组,并使用 CopyTo 方法从数组中间开始复制数组元素。再次使用 Queue<(Of <(T>)>) 构造函数创建第二个队列副本,此队列在开始处包含三个 null 元素。

使用 Contains 方法显示字符串“four”在第一个队列副本中,然后使用 Clear 方法清除此副本并由 Count 属性显示该队列为空。

using System;
using System.Collections.Generic;

class Example
{
    public static void Main()
    {
        Queue<string> numbers = new Queue<string>();
        numbers.Enqueue("one");
        numbers.Enqueue("two");
        numbers.Enqueue("three");
        numbers.Enqueue("four");
        numbers.Enqueue("five");

        // A queue can be enumerated without disturbing its contents.
        foreach( string number in numbers )
        {
            Console.WriteLine(number);
        }

        Console.WriteLine("\nDequeuing '{0}'", numbers.Dequeue());
        Console.WriteLine("Peek at next item to dequeue: {0}",
            numbers.Peek());
        Console.WriteLine("Dequeuing '{0}'", numbers.Dequeue());

        // Create a copy of the queue, using the ToArray method and the
        // constructor that accepts an IEnumerable<T>.
        Queue<string> queueCopy = new Queue<string>(numbers.ToArray());

        Console.WriteLine("\nContents of the first copy:");
        foreach( string number in queueCopy )
        {
            Console.WriteLine(number);
        }

        // Create an array twice the size of the queue and copy the
        // elements of the queue, starting at the middle of the
        // array.
        string[] array2 = new string[numbers.Count * 2];
        numbers.CopyTo(array2, numbers.Count);

        // Create a second queue, using the constructor that accepts an
        // IEnumerable(Of T).
        Queue<string> queueCopy2 = new Queue<string>(array2);

        Console.WriteLine("\nContents of the second copy, with duplicates and nulls:");
        foreach( string number in queueCopy2 )
        {
            Console.WriteLine(number);
        }

        Console.WriteLine("\nqueueCopy.Contains(\"four\") = {0}",
            queueCopy.Contains("four"));

        Console.WriteLine("\nqueueCopy.Clear()");
        queueCopy.Clear();
        Console.WriteLine("\nqueueCopy.Count = {0}", queueCopy.Count);
    }
}

/* This code example produces the following output:

one
two
three
four
five

Dequeuing 'one'
Peek at next item to dequeue: two
Dequeuing 'two'

Contents of the copy:
three
four
five

Contents of the second copy, with duplicates and nulls:



three
four
five

queueCopy.Contains("four") = True

queueCopy.Clear()

queueCopy.Count = 0
*/


System..::.Object
  System.Collections.Generic..::.Queue<(Of <(T>)>)

此类型的公共静态(在 Visual Basic 中为 Shared)成员是线程安全的。但不能保证任何实例成员是线程安全的。

只要不修改该集合,Queue<(Of <(T>)>) 就可以同时支持多个阅读器。即便如此,从头到尾对一个集合进行枚举本质上并不是一个线程安全的过程。若要确保枚举过程中的线程安全,可以在整个枚举过程中锁定集合。若要允许多个线程访问集合以进行读写操作,则必须实现自己的同步。

 

文章摘自

posted @ 2008-11-21 13:53 Freeman Shen 阅读(194) 评论(0) 编辑
什么是信号量(Semaphore)

    如果你已经了解信号量(Semaphore)的概念了,请跳过这一段。

    信号量(Semaphore)是在多线程环境下使用的一种设施, 它负责协调各个线程, 以保证它们能够正确、合理的使用公共资源。

    我们来看看一个停车场是怎样运作的。为了简单起见,假设停车场只有三个车位,一开始三个车位都是空的。这是如果同时来了五辆车,看门人允许其中三辆不受阻碍的进入,然后放下车拦,剩下的车则必须在入口等待,此后来的车也都不得不在入口处等待。这时,有一辆车离开停车场,看门人得知后,打开车拦,放入一辆,如果又离开两辆,则又可以放入两辆,如此往复。

    在这个停车场系统中,车位是公共资源,每辆车好比一个线程,看门人起的就是信号量的作用。

    更进一步,信号量的特性如下:信号量是一个非负整数(车位数),所有通过它的线程(车辆)都会将该整数减一(通过它当然是为了使用资源),当该整数值为零时,所有试图通过它的线程都将处于等待状态。在信号量上我们定义两种操作: Wait(等待) 和 Release(释放)。 当一个线程调用Wait等待)操作时,它要么通过然后将信号量减一,要么一自等下去,直到信号量大于一或超时。Release(释放)实际上是在信号量上执行加操作,对应于车辆离开停车场,该操作之所以叫做“释放”是应为加操作实际上是释放了由信号量守护的资源。(引自:.Net 下信号量(Semaphore)的一种实现)

 

NET Framework 类库

Semaphore 类

注意:此类在 .NET Framework 2.0 版中是新增的。

限制可同时访问某一资源或资源池的线程数。

命名空间:System.Threading
程序集:System(在 system.dll 中)

Note注意

应用于此类的 HostProtectionAttribute 属性 (Attribute) 具有下面的 Resources 属性 (Property) 值:Synchronization | ExternalThreading
HostProtectionAttribute 不影响桌面应用程序(桌面应用程序一般通过双击图标,键入命令或在浏览器中输入 URL 启动)。有关更多信息,
请参见 HostProtectionAttribute 类或 SQL Server 编程和宿主保护属性

使用 Semaphore 类可控制对资源池的访问。线程通过调用 WaitOne 方法(从 WaitHandle 类继承)进入信号量,并通过调用 Release 方法释放信号量。

信号量的计数在每次线程进入信号量时减小,在线程释放信号量时增加。当计数为零时,后面的请求将被阻塞,直到有其他线程释放信号量。当所有的线程都已释放信号量时,计数达到创建信号量时所指定的最大值。

被阻止的线程并不一定按特定的顺序(如 FIFO 或 LIFO)进入信号量。

线程可通过重复调用 WaitOne 方法多次进入信号量。为释放这些入口中的部分或全部,线程可多次调用无参数的 Release 方法重载,也可以调用 Release(Int32) 方法重载来指定要释放的入口数。

Semaphore 类不对 WaitOneRelease 调用强制线程标识。程序员负责确保线程释放信号量的次数不能太多。例如,假定信号量的最大计数为 2,并且线程 A 和线程 B 同时进入信号量。如果线程 B 中的编程错误导致它两次调用 Release,则两次调用都成功。这样,信号量的计数已满,当线程 A 最终调用 Release 时便会引发 SemaphoreFullException

信号量分为两种类型:局部信号量和已命名的系统信号量。如果您使用接受名称的构造函数创建 Semaphore 对象,则该对象与具有该名称的操作系统信号量关联。已命名的系统信号量在整个操作系统中都可见,可用于同步进程活动。您可以创建多个 Semaphore 对象来表示同一个已命名的系统信号量,也可以使用 OpenExisting 方法打开现有的已命名系统信号量。

局部信号量仅存在于您的进程内。您的进程中任何引用局部 Semaphore 对象的线程都可以使用它。每个 Semaphore 对象都是一个单独的局部信号量。

下面的代码示例创建一个最大计数为 3、初始计数为 0 的信号量。该示例启动五个线程,这些线程阻止该信号量的等待。主线程使用 Release(Int32) 方法重载,以便将信号量计数增加为其最大值,从而允许三个线程进入该信号量。每个线程都使用 System.Threading.Thread.Sleep 方法等待一秒钟以便模拟工作,然后调用 Release 方法重载以释放信号量。每次释放信号量时,都显示前一个信号量计数。控制台消息对信号量的使用进行跟踪。每个线程的模拟工作间隔都稍有增加,以使输出更为易读。

using System;
using System.Threading;

public class Example
{
    // A semaphore that simulates a limited resource pool.
    //
    private static Semaphore _pool;

    // A padding interval to make the output more orderly.
    private static int _padding;

    public static void Main()
    {
        // Create a semaphore that can satisfy up to three
        // concurrent requests. Use an initial count of zero,
        // so that the entire semaphore count is initially
        // owned by the main program thread.
        //
        _pool = new Semaphore(0, 3);

        // Create and start five numbered threads.
        //
        for(int i = 1; i <= 5; i++)
        {
            Thread t = new Thread(new ParameterizedThreadStart(Worker));

            // Start the thread, passing the number.
            //
            t.Start(i);
        }

        // Wait for half a second, to allow all the
        // threads to start and to block on the semaphore.
        //
        Thread.Sleep(500);

        // The main thread starts out holding the entire
        // semaphore count. Calling Release(3) brings the
        // semaphore count back to its maximum value, and
        // allows the waiting threads to enter the semaphore,
        // up to three at a time.
        //
        Console.WriteLine("Main thread calls Release(3).");
        _pool.Release(3);

        Console.WriteLine("Main thread exits.");
    }

    private static void Worker(object num)
    {
        // Each worker thread begins by requesting the
        // semaphore.
        Console.WriteLine("Thread {0} begins " +
            "and waits for the semaphore.", num);
        _pool.WaitOne();

        // A padding interval to make the output more orderly.
        int padding = Interlocked.Add(ref _padding, 100);

        Console.WriteLine("Thread {0} enters the semaphore.", num);
       
        // The thread's "work" consists of sleeping for
        // about a second. Each thread "works" a little
        // longer, just to make the output more orderly.
        //
        Thread.Sleep(1000 + padding);

        Console.WriteLine("Thread {0} releases the semaphore.", num);
        Console.WriteLine("Thread {0} previous semaphore count: {1}",
            num, _pool.Release());
    }
}

 

posted @ 2008-11-21 13:41 Freeman Shen 阅读(484) 评论(0) 编辑