关于“C#使用Monitor类实现线程同步”的完整攻略,以下为具体内容:
Monitor类简介
Monitor类属于System.Threading命名空间,它提供了一种同步机制以控制对共享资源的访问。Monitor实现相对于lock语句的优点在于使用了更低层次的同步原语,因此可以更细粒度地控制线程的同步。
Monitor类的基本用法
首先是使用Monitor进入临界区,代码如下:
public void Enter(object obj)
{
Monitor.Enter(obj);
try
{
// 加锁过程中的业务代码
}
finally
{
Monitor.Exit(obj);
}
}
Monitor.Enter方法用于进入临界区,需要传入一个obj作为锁对象;try代码块内的业务代码是在进入临界区后要执行的操作,比如读取共享资源、修改共享资源等操作;finally代码块内的Monitor.Exit方法用于离开临界区。
接下来是Monitor.Wait方法的使用,代码如下:
public void Wait(object obj)
{
Monitor.Enter(obj);
try
{
// do something before wait
Monitor.Wait(obj);
// do something after wait
}
finally
{
Monitor.Exit(obj);
}
}
Monitor.Wait方法用于进入一个等待状态,并释放obj所持有的锁,直到其他线程调用Monitor.Pulse或Monitor.PulseAll方法来唤醒它。在wait前需要先进入临界区,等待过程中会释放锁,直到被唤醒后才会重新获得锁。
最后是Monitor.Pulse和Monitor.PulseAll方法的使用,代码如下:
public void Pulse(object obj)
{
Monitor.Enter(obj);
try
{
// do something before pulse
Monitor.Pulse(obj);
// do something after pulse
}
finally
{
Monitor.Exit(obj);
}
}
public void PulseAll(object obj)
{
Monitor.Enter(obj);
try
{
// do something before pulse
Monitor.PulseAll(obj);
// do something after pulse
}
finally
{
Monitor.Exit(obj);
}
}
Monitor.Pulse方法用于唤醒一个处于等待状态的线程,Monitor.PulseAll方法用于唤醒所有处于等待状态的线程。在调用Pulse或PulseAll方法前需要先进入临界区。
示例1
下面是一个生产者-消费者模型的示例,使用Monitor类实现线程同步:
class Program
{
static List<int> buffer = new List<int>();
static int bufferSize = 5;
static object lockObj = new object();
static void Main(string[] args)
{
Thread producer = new Thread(new ThreadStart(Producer));
Thread consumer = new Thread(new ThreadStart(Consumer));
producer.Start();
consumer.Start();
}
static void Producer()
{
int i = 0;
while (true)
{
lock (lockObj)
{
if (buffer.Count >= bufferSize)
{
Monitor.Wait(lockObj);
}
buffer.Add(i);
Console.WriteLine("producer produced: " + i);
i++;
Monitor.PulseAll(lockObj);
}
Thread.Sleep(1000);
}
}
static void Consumer()
{
while (true)
{
lock (lockObj)
{
if (buffer.Count <= 0)
{
Monitor.Wait(lockObj);
}
int value = buffer.First();
buffer.RemoveAt(0);
Console.WriteLine("consumer consumed: " + value);
Monitor.PulseAll(lockObj);
}
Thread.Sleep(1000);
}
}
}
在这个示例中,使用了一个buffer List作为共享资源存储生产的数据。当buffer满时,生产者线程会等待消费者将数据取走;当buffer为空时,消费者线程会等待生产者产生数据。在每次修改共享资源后都需要使用PulseAll方法唤醒处于等待状态的线程。
示例2
下面是另一个示例,在主线程中创建两个子线程并分别调用两个函数,这两个函数使用Monitor实现对一个全局变量num的访问:
class Program
{
static int num = 0;
static object lockObj = new object();
static void Main(string[] args)
{
Thread thread1 = new Thread(new ThreadStart(Function1));
Thread thread2 = new Thread(new ThreadStart(Function2));
thread1.Start();
thread2.Start();
}
static void Function1()
{
for (int i = 0; i < 10; i++)
{
lock (lockObj)
{
num++;
Console.WriteLine("Thread 1: num = " + num);
}
Thread.Sleep(1000);
}
}
static void Function2()
{
for (int i = 0; i < 10; i++)
{
lock (lockObj)
{
num--;
Console.WriteLine("Thread 2: num = " + num);
}
Thread.Sleep(1000);
}
}
}
在这个示例中,使用了一个全局变量num作为共享资源。在每次修改num的值时,需要进入临界区,修改完毕后再释放锁。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C#使用Monitor类实现线程同步 - Python技术站