这两天由于学习的需要,学了一下C#的多线程,并写了个经典生产者与消费者的案例,但从中也发现了一个问题,总体上感觉C#比java在各个方面来说,总是有些不如,也许是长期使用java和刚刚接触C#吧,存在些偏见,言归正转,解决这个多线程问题,有以下几步骤:
1、使用多线程遇到的问题:解决诸如购票、候车等问题时,肯定是并行工作的,当共同访问一块数据时,如果不加锁的机制的话,肯定会造成数据不一致。
2、所谓的线程同步,就是通过加锁的机制,使得同一段代码,某一时刻只有一线程在访问,也就是有个先来后到,可以多个同时读数据,但不能同时写数据。
3、C#中的同步问题的解决,有lock,Monitor,Mutex等方法来解决。
4、具体的代码分析和实现
首先要进行明确的面向对象分析,然后进行面向对象编码。在这里只将最核心的同步代码如些:
//此类用来模拟篮子,用来放馒头,并将它比作栈来处理,可以先进后出,后进先出的进行操作
class Basket//用篮子模拟放馒头的集合
{
public static int max_capability = 0;//篮子中最大可以放的馒头数目
public ManTou[] manTous = null;//声明馒头的一个数
public static int index=0;//刚开始时的馒头的数量,此时表明篮子中没有馒头,特别指出它始终指/////向馒头的上一个空格
public void push(ManTou mt,string producer_name)//模拟栈的放入(压入)操作,即将新生产的一个//馒头压入篮子中
{
lock (this)//此处采用简单常用的lock来实现线程的同步
{
while (index >= max_capability)//判断是不是篮子已经满了,即数目到了max_capability.
{
Console.WriteLine(producer_name + "等待中");//为了更好看到输出效果
Monitor.Wait(this);//此时会释放掉当前对象(this)的锁,当有调用pulseAll时重新回到//此处,并重新得到当前对象(this)锁
Console.WriteLine(producer_name + "唤醒了");
}
manTous[index++] = mt;//将新生成的ManTou对象放入篮子中
Console.WriteLine(producer_name+"-生产了: "+mt);
Monitor.PulseAll(this);//唤醒等待在此对象上的所有线程
}
}
public ManTou pop(string consumer_name)//模拟栈的拿出操作,也就是拿出最顶上的馒头
{
ManTou mt = null;
lock (this)
{
while (index == 0)
{
Console.WriteLine(consumer_name+"等待中");
Monitor.Wait(this);
Console.WriteLine(consumer_name + "唤醒了");
}
mt = manTous[--index];
Monitor.PulseAll(this);
Console.WriteLine(consumer_name + "-消费了 : " + mt);
return mt;//此处有待考虑
}
}
public Basket(int max_capability)
{
Basket.max_capability = max_capability;
manTous=new ManTou[max_capability];
}
}
5、重点在于理解lock与Monitor的配合使用,这与java的obj.wait和obj.notifyAll相对应的,试试吧。
这里的代码只是核心部分,如果还有不明白的,可以留言联系,希望对你的学习有帮助。