互斥锁:
//互斥锁是一个互斥的同步对象,这意味着在同一个时间有且仅有一个线程可以获取它。互斥锁适用于下列情况:
//一个共享资源每次只能被一个线程使用。例如:考虑一个由多个进程共享的日志文件,任意时刻只能有一个进程对//该文件执行写入操作。互斥锁是解决此类问题的最佳同步工具。
//互斥锁由System.Threading.Mutex类支持。该类有多个构造函数,其中最常用的两个是:
//publi Mutex()
//publi Mutex(bool owned)
//第一个版本创建一个处于未获取状态的互斥锁。
//在第二个版本中,如果owned为true,互斥锁的初始状态就是被主调线程所获取,否则处于未获取状态。
//要获取一个互斥锁,应当调用互斥锁上的WaitOne()方法。该方法继承于System.Threading.WaitHandle
//下面是它的最简单形式:
//public bool WaitOne();
//它将处于等待状态知道所调用的互斥锁可以被获取。因此该方法将阻塞主线程直到指定的互斥锁可用。该方法总是返回true.
//如果代码不再需要拥有互斥锁,可以调用下面的ReleaseMutex()方法来释放它:
//public void ReleaseMutex();
//在互斥锁上调用该方法将使得互斥锁被释放,从而允许该互斥锁被另一个线程所获取。
//要使用互斥锁来同步对共享资源的访问,需要使用WaitOne()和ReleaseMutex如下面的代码所示。
//Mutex myMtx = new Mutex();
//myMtx.WaitOne();
//myMtx.ReleaseMutex();
//在调用WaitOne()方法是,线程的执行将挂起直到获取互斥锁。在调用ReleaseMutex方法时,互斥锁将被释放,从而另一个线程可以获取它。
//通过这种方法,共享资源可以被限制为每次只允许一个线程访问。
public class ShardRes
{
public static int Count = 0;
public static Mutex Mtx = new Mutex();
}
class IncThread
{
int num;
public Thread Thrd;
public IncThread(string name, int n)
{
Thrd = new Thread(new ThreadStart(this.Run));
num = n;
Thrd.Name = name;
Thrd.Start();
}
void Run()
{
Console.WriteLine(Thrd.Name + " is waiting for the mutex");
ShardRes.Mtx.WaitOne();
Console.WriteLine(Thrd.Name + " acquires the mutex.");
do
{
Thread.Sleep(500);
ShardRes.Count++;
Console.WriteLine("In " + Thrd.Name + ",ShardRes.Count is" + ShardRes.Count);
num--;
}
while (num > 0);
Console.WriteLine(Thrd.Name + " releases the mutex.");
ShardRes.Mtx.ReleaseMutex();
}
}
public class DecThread
{
int num;
public Thread Thrd;
public DecThread(string name, int n)
{
Thrd = new Thread(new ThreadStart(this.Run));
num = n;
Thrd.Name = name;
Thrd.Start();
}
public void Run()
{
Console.WriteLine(Thrd.Name + " is waiting for the mutex");
ShardRes.Mtx.WaitOne();
do
{
Thread.Sleep(500);
ShardRes.Count--;
Console.WriteLine("In " + Thrd.Name + ",SharedRes.count is " + ShardRes.Count);
num--;
} while (num > 0);
Console.WriteLine(Thrd.Name + " releases the mutex.");
ShardRes.Mtx.ReleaseMutex();
}
}
class ThreadFive
{
public static void Main(string[] arg)
{
Console.WriteLine("ok");
IncThread mt1 = new IncThread("Increment Thread", 5);
Thread.Sleep(1);
DecThread mt2 = new DecThread("Decrement Thread", 5);
mt1.Thrd.Join();
mt2.Thrd.Join();
Console.Read();
}
}
信号量:
//信号量类似于互斥锁,但它可以允许多个线程同时访问一个共享资源。因此在同步一个资源集合的时候,信号量就显得非常有用。
//信号量通过一个计数器来控制对共享资源的访问。如果计数器大于0,那么就iu允许访问。如果计数器等于0,就拒绝访问。计数
//器累计的是“许可证”的个数。因此,为了访问某个资源,线程将阻塞直到得到一个许可证。
//信号量特别使用于下列情况:一个由“组(group)”或者"池(pool)"构成的共享资源。例如一个网络连接的集合,其中每一个连接
//都可以用于通信,这就是一个资源池。需要网络连接的线程并不关心它获取的是哪一个网络连接。在这种情况下,信号量提供了
//一种方便的机制来管理对连接的访问。
//信号量是由System.Threading.Semaphore实现的。它有多个构造函数,最简单形式为:
//public Semaphore(int initial,int max)
//其中,initial指定了信号量许可证计数器的初始值,它指定可用的许可证数目。计数器的最大值在max中传递。max地表了信号量
//最多拥有的许可证数目.initial的值指定了初始情况下有多少个许可证可用。
//获取信号量使用 WaitOne()
//不再需要使用信号量使用Release()方法释放。
//注意:
//线程在调用Release()之前可以多次调用WaitOne().但是,在释放许可证之前,WaitOne()的调用次数必须和Release()的调用次数一致。
//或者,也可以调用Release(int)形式,传入WaitOne()的调用次数。
class ThreadSix
{
public Thread Thr;
static Semaphore sem = new Semaphore(2, 2);
public ThreadSix(string name)
{
Thr = new Thread(this.Run);
Thr.Name = name;
Thr.Start();
}
public void Run()
{
Console.WriteLine(Thr.Name + " is waiting for permit");
sem.WaitOne();
Console.WriteLine(Thr.Name + " is acquires for permit");
for (char ch = 'A'; ch < 'D'; ch++)
{
Console.WriteLine(Thr.Name + " : " + ch + " ");
Thread.Sleep(500);
}
Console.WriteLine(Thr.Name + " releases a permit.");
sem.Release();
}
}
public class SemaphoreDemo
{
static void Main(string[] arg)
{
ThreadSix t1 = new ThreadSix("one");
ThreadSix t2 = new ThreadSix("two");
ThreadSix t3 = new ThreadSix("three");
t1.Thr.Join();
t2.Thr.Join();
t3.Thr.Join();
Console.Read();
}
}
//使用事件实现同步。
//同步事件有两种类型:ManualResetEvent(手工重置) AutoResetEvent(自动重置)
//事件处理非常简单。对于ManualResetEvent,其处理过程处理如下:等待某个事件
//的线程简单的代表该事件的事件对象上调用WaitOne();如果事件对象处于已发出
//信号状态,WaitOne将立即返回。它将挂起主调线程直到事件发出信号。在另一个线程执行事件之后,该线程通过调用
//Set()来把事件对象置于已发出信号状态,对WaitOne()的调用将返回,并且第一个线程恢复执行。
//调用Reset()将该事件重置为未发出信号状态。
public class ThreadSeven
{
public Thread Thrd;
ManualResetEvent mre;
public ThreadSeven(string name, ManualResetEvent evt)
{
Thrd = new Thread(this.Run);
Thrd.Name = name;
mre = evt;
Thrd.Start();
}
public void Run()
{
Console.WriteLine("Inside thread " + Thrd.Name);
for (int i = 0; i < 5; i++)
{
Console.WriteLine(Thrd.Name);
Thread.Sleep(500);
}
Console.WriteLine(Thrd.Name + " Done!");
mre.Set();
}
}
class ManualEventDemo
{
static void Main()
{
ManualResetEvent mre = new ManualResetEvent(false);
ThreadSeven mt1 = new ThreadSeven("Event Thread 1", mre);
Console.WriteLine("Main thread is waiting first event.");
mre.WaitOne();
Console.WriteLine("Main thread received first event.");
mre.Reset();
mt1 = new ThreadSeven("Event Thread 2", mre);
mre.WaitOne();
Console.WriteLine("Main Thread received second event.");
Console.Read();
}
}