多线程对共同资源的访问,往往会造成数据的混乱和不可预料的结果,因此一般需要加锁访问进行互斥访问。
所谓“互斥访问”是指,一段代码或者公共变量,在一个时刻只允许一个线程去访问,其他的线程需要等待,直到改线程处理完毕并通知下一个等待的线程去处理。
1、可以用“Lock”来提供代码的互斥访问:
lock (一个类的示例、静态变量的类名)
{
// 代码
}
2、可以用“Monitor”来提供变量的互斥访问:
int money;
Monitor.Enter(money);
// money++或者money--;
Monitor.Exit(money);
Monitor的工作原理是:Monitor维护了两个队列,一个是预备队列,其中保存准备获取锁的线程;另一个是等待队列,保存正在等待这个对象状态改变的线程。当锁被一个线程释放时,调用Monitor.Pulse()方法,将等待队列中的第一个线程放到预备队列中。
下面是一个使用Lock和Monitor的例子:
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
namespace Demo
{
public class ProductClass
{
int products;
bool enableGet = false; // If ture, consumer can get product, otherwise producer is producing.
public int GetProducts()
{
lock (this)
{
if (!enableGet)
{
try
{
Monitor.Wait(this);
}
catch (SynchronizationLockException ex)
{
Console.WriteLine("[SynchronizationLockException Error]: " + ex.ToString());
}
catch (ThreadInterruptedException ex)
{
Console.WriteLine("[ThreadInterruptedException Error]: " + ex.ToString());
}
}
Console.WriteLine("Consume: {0}", products);
// Reset to be false after getting products.
enableGet = false;
// Notify producing thread to produce products
Monitor.Pulse(this);
}
return products;
}
public void ProduceProducts(int products)
{
lock (this)
{
if (enableGet)
{
try
{
Monitor.Wait(this);
}
catch (SynchronizationLockException ex)
{
Console.WriteLine("[SynchronizationLockException Error]: " + ex.ToString());
}
catch (ThreadInterruptedException ex)
{
Console.WriteLine("[ThreadInterruptedException Error]: " + ex.ToString());
}
}
this.products = products;
Console.WriteLine("Produce: {0}", products);
enableGet = true;
Monitor.Pulse(this);
}
}
}
public class Producer
{
ProductClass aProductClass;
int produceTimes = 1;
public Producer(ProductClass aProductClass, int produceTimes)
{
this.aProductClass = aProductClass;
this.produceTimes = produceTimes;
}
public void ThreadRun()
{
for (int i = 0; i < produceTimes; i++)
{
aProductClass.ProduceProducts(i);
}
}
}
public class Consumer
{
ProductClass aProductClass;
int getProductTimes = 1;
public Consumer(ProductClass aProductClass, int getProductTimes)
{
this.aProductClass = aProductClass;
this.getProductTimes = getProductTimes;
}
public void ThreadRun()
{
int returnValue;
for (int i = 0; i < getProductTimes; i++)
{
returnValue = aProductClass.GetProducts();
}
}
}
class Program
{
static void Main(string[] args)
{
ProductClass aProductClass = new ProductClass();
Producer aProducer = new Producer(aProductClass, 20);
Consumer aConsumer = new Consumer(aProductClass, 20);
Thread produceThread = new Thread(new ThreadStart(aProducer.ThreadRun));
Thread consumeThread = new Thread(new ThreadStart(aConsumer.ThreadRun));
try
{
produceThread.Start();
consumeThread.Start();
produceThread.Join();
consumeThread.Join();
Console.ReadLine();
}
catch (ThreadStateException ex)
{
Console.WriteLine("[ThreadStateException Error]: " + ex.ToString());
}
catch (ThreadInterruptedException ex)
{
Console.WriteLine("[ThreadInterruptedException Error]: " + ex.ToString());
}
}
}
}
C#多线程:互斥访问与Lock/Monitor机制
本文介绍了C#中多线程访问共享资源时可能导致的数据混乱问题,强调了互斥访问的重要性。通过Lock和Monitor两种方式实现线程间的互斥,确保同一时刻只有一个线程能访问特定代码或变量。Monitor维护了预备队列和等待队列,释放锁时会唤醒等待队列中的线程。示例代码展示了Lock和Monitor的用法。
5950

被折叠的 条评论
为什么被折叠?



