C# Mutex,Semaphore

Mutex

Mutex 类似于C# lock, 区别在于一个Mutex可以在多个进程间使用.也就是说Mutex既是computer-wide又是application-wide.

注意: 获取和释放Mutex大概比lock要多五十倍时间.

调用WaitOne()来获得锁, ReleaseMutex()来解除锁.关闭或者杀死Mutex会自动释放掉锁.和lock一样, Mutex只能从拥有它的线程释放掉.

cross-process Mutex的常见用处是用来确保某个程序只有一个实例在运行.

代码如下:

class OneAtATimePlease
{
static void Main()
{
// Naming a Mutex makes it available computer-wide. Use a name that's
// unique to your company and application (e.g., include your URL).
using (var mutex = new Mutex (false, "oreilly.com OneAtATimeDemo"))
{
// Wait a few seconds if contended, in case another instance
// of the program is still in the process of shutting down.
if (!mutex.WaitOne (TimeSpan.FromSeconds (3), false))
{
Console.WriteLine ("Another instance of the app is running. Bye!");
return;
}
RunProgram();
}
}
static void RunProgram()
{
Console.WriteLine ("Running. Press Enter to exit");
Console.ReadLine();
}
}

在Terminal Services下运行时, computer-wide Mutex 只有在同一个terminal server session 中的程序可见, 如果要让它在所有 Terminal Serverces sessions 可见, 则需要在它名字前面加上\.

Semaphore

一个信号量就如同夜总会:它有固定的容量。每次装满的时候,外面的人就不能进去了,需要在门外排队。没离开一个人,队列中第一个人就可以进去。构造器需要至少两个参数:一是剩余的空间,二是总的容量。

容量为1的信号量和Mutex或者lock类似,但是信号量没有“所有者”,即信号量是线程无关的(Thread-agnostic)。 任何线程都可以Release一个信号量。而Mutex和lock则只有拥有它的线程可以Release它。

注意:有两个功能类似的信号量。Semaphore和SemaphoreSlim。后者在.net 4中被引进,为实现并行开发的低延迟要求而优化。在传统多线程环境也可以使用,它提供一个选项来停止等待。然而他不能用来进行跨线程的信号操作。(Mutex和Semaphore都是可以跨线程的。)

Semaphore要求1ms来调用WaitOne或者Release,而SemaphoreSlim只要求1/4ms。

信号量用来降低同步很有效--防止太多线程同步执行同一个代码块。例子如下,限制每次只有三个线程进行同步,其他线程等待。

class TheClub      // No door lists!
{
  static SemaphoreSlim _sem = new SemaphoreSlim (3);    // Capacity of 3
 
  static void Main()
  {
    for (int i = 1; i <= 5; i++) new Thread (Enter).Start (i);
  }
 
  static void Enter (object id)
  {
    Console.WriteLine (id + " wants to enter");
    _sem.Wait();
    Console.WriteLine (id + " is in!");           // Only three threads
    Thread.Sleep (1000 * (int) id);               // can be here at
    Console.WriteLine (id + " is leaving");       // a time.
    _sem.Release();
  }
}

生产中消费者队列:

using System;
using System.Threading;
using System.Collections.Generic;
 
class ProducerConsumerQueue : IDisposable
{
  EventWaitHandle _wh = new AutoResetEvent (false);
  Thread _worker;
  readonly object _locker = new object();
  Queue<string> _tasks = new Queue<string>();
 
  public ProducerConsumerQueue()
  {
    _worker = new Thread (Work);
    _worker.Start();
  }
 
  public void EnqueueTask (string task)
  {
    lock (_locker) _tasks.Enqueue (task);
    _wh.Set();
  }
 
  public void Dispose()
  {
    EnqueueTask (null);     // Signal the consumer to exit.
    _worker.Join();         // Wait for the consumer's thread to finish.
    _wh.Close();            // Release any OS resources.
  }
 
  void Work()
  {
    while (true)
    {
      string task = null;
      lock (_locker)
        if (_tasks.Count > 0)
        {
          task = _tasks.Dequeue();
          if (task == null) return;
        }
      if (task != null)
      {
        Console.WriteLine ("Performing task: " + task);
        Thread.Sleep (1000);  // simulate work...
      }
      else
        _wh.WaitOne();         // No more tasks - wait for a signal
    }
  }
}

常见的 concurrent collection 通常是用 mutex, reset event 来对 normal collection 进行控制。

如: 

public T Dequeue(int timeout)
{
if(resetEvent.WaitOne(timeout,false)==true)
{
	if(mutex.WaitOne(timeout,false)==true)
	{
		return base.Dequeue();
	}
}
}


你可能感兴趣的:(C# Mutex,Semaphore)