Semaphore

http://www.albahari.com/threading/part2.aspx#_Semaphore

A semaphore is like a nightclub: it has a certain capacity, enforced by a bouncer.

Once it’s full, no more people can enter, and a queue builds up outside.

Then, for each person that leaves, one person enters from the head of the queue.

The constructor requires a minimum of two arguments: the number of places currently available in the nightclub and the club’s total capacity.

 

A semaphore with a capacity of one is similar to a Mutex or lock, except that the semaphore has no “owner” — it’s thread-agnostic.

Any thread can call Release on a Semaphore, whereas with Mutex and lock, only the thread that obtained the lock can release it.

 

Note:

There are two functionally similar versions of this class: Semaphore and SemaphoreSlim.

The latter was introduced in Framework 4.0 and has been optimized to meet the low-latency潜在因素 demands需求 of parallel programming.

It’s also useful in traditional multithreading because it lets you specify a cancellation token when waiting. It cannot, however, be used for interprocess进程间的 signaling.

Semaphore incurs招致 about 1 microsecond in calling WaitOne or ReleaseSemaphoreSlim incurs about a quarter of that.

 

Semaphores can be useful in limiting concurrency — preventing too many threads from executing a particular piece of code at once.

In the following example, five threads try to enter a nightclub that allows only three threads in at once:

 

 

https://msdn.microsoft.com/en-us/library/system.threading.semaphore(v=vs.110).aspx

Limits the number of threads that can access a resource or pool of resources concurrently.

Remarks

Use the Semaphore class to control access to a pool of resources.

Threads enter the semaphore by calling the WaitOne method, which is inherited from the WaitHandle class, and release the semaphore by calling the Release method.

 

The count on a semaphore is decremented each time a thread enters the semaphore, and incremented when a thread releases the semaphore.

When the count is zero, subsequent requests block until other threads release the semaphore.

When all threads have released the semaphore, the count is at the maximum value specified when the semaphore was created.

 

There is no guaranteed order, such as FIFO or LIFO, in which blocked threads enter the semaphore.

 

A thread can enter the semaphore multiple times, by calling the WaitOne method repeatedly.

To release some or all of these entries, the thread can call the parameterless Release() method overload multiple times,

or it can call the Release(Int32) method overload that specifies the number of entries to be released.

 

The Semaphore class does not enforce thread identity一致 on calls to WaitOne or Release.

It is the programmer's responsibility to ensure that threads do not release the semaphore too many times.

For example, suppose假设 a semaphore has a maximum count of two, and that thread A and thread B both enter the semaphore.

If a programming error in thread B causes it to call Release twice, both calls succeed.

The count on the semaphore is full, and when thread A eventually calls Release, a SemaphoreFullException is thrown.

 

Semaphores are of two types: local semaphores and named system semaphores.

If you create a Semaphore object using a constructor that accepts a name, it is associated with an operating-system semaphore of that name.

Named system semaphores are visible throughout the operating system, and can be used to synchronize the activities of processes.

You can create multiple Semaphore objects that represent the same named system semaphore, and you can use the OpenExisting method to open an existing named system semaphore.

 

A local semaphore exists only within your process.

It can be used by any thread in your process that has a reference to the local Semaphoreobject.

Each Semaphore object is a separate local semaphore.

 

Examples

The following code example creates a semaphore with a maximum count of three and an initial count of zero.

The example starts five threads, which block waiting for the semaphore.

The main thread uses the Release(Int32) method overload to increase the semaphore count to its maximum, allowing three threads to enter the semaphore.

Each thread uses the Thread.Sleep method to wait for one second, to simulate模仿 work, and then calls the Release() method overload to release the semaphore.

Each time the semaphore is released, the previous semaphore count is displayed.Console messages track semaphore use.

The simulated work interval间隔 is increased slightly for each thread, to make the output easier to read.

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

        /// <summary>
        /// A padding interval to make the output more orderly.
        /// </summary>
        private static int padding;

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

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

            Console.WriteLine("Thread {0} enters the semaphore.", number);

            //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 + tempPadding);

            Console.WriteLine("Thread {0} releases the semaphore.", number);
            int previousCount = semaphore.Release();
            Console.WriteLine("Thread {0} previous semaphore count: {1}", number,previousCount);
        }

        internal static void Method()
        {
            //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.
            semaphore = new Semaphore(0, 3);

            //Create and start five numbered threads. 
            for (int i = 1; i <= 5; i++)
            {
                Thread thread = new Thread(Worker);
                //Start the thread, passing the number.
                thread.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).");
            semaphore.Release(3);

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

 

posted @ 2016-03-07 10:29  ChuckLu  阅读(345)  评论(0编辑  收藏  举报