生产者-消费者问题是说明多线程同步&互斥的经典问题,也是最近偶操作系统老师的一道编程作业。
在C#的System.Threading命名空间中,有可以用来解决这个问题的对象(Monitor、Mutex等),下面是一个我写的控制台程序,包括了大多数要用到的方法(但并不完全满足原问题的要求的,想想要怎么改动一下吧):
最后再放上完成图形界面后的一张效果图,呵呵!
问题描述:一个仓库可以存放K件物品。生产者每生产一件产品,将产品放入仓库,仓库满了就停止生产。消费者每次从仓库中去一件物品,然后进行消费,仓库空时就停止消费。
在C#的System.Threading命名空间中,有可以用来解决这个问题的对象(Monitor、Mutex等),下面是一个我写的控制台程序,包括了大多数要用到的方法(但并不完全满足原问题的要求的,想想要怎么改动一下吧):
//生产者-消费者问题
//by BodeSmile
using System;
using System.Threading;
namespace Producer_Consumer
{
class Producer_Consumer
{
public const int N = 100; //缓冲区中的槽数目
public static Mutex mutex; //控制对临界区的访问
public static int empty = N; //计数缓冲区的空槽数目
public static int full = 0; //计数缓冲区的满槽数目
public static int [] buffer = new int[N]; //模拟缓冲区
public static int cnt=0; //记录模拟缓冲区的起始位置
public void Insert_Item(int tp) //将(新)数据项放入缓冲区中
{
buffer[(cnt+full)%N]=tp;
}
public int Remove_Item() //将(新)数据项放入缓冲区中
{
int tp=buffer[cnt];
cnt=(cnt+1)%N;
return tp;
}
public void Down(ref int tp)
{
Monitor.Enter(this); //以下操作是不可打断的
while(tp<=0)
{
Monitor.Pulse(this);
Monitor.Wait(this);
}
tp--;
Monitor.Exit(this); //以上操作是不可打断的
}
public void Up(ref int tp)
{
Monitor.Enter(this); //以下操作是不可打断的
tp++;
Monitor.Exit(this); //以上操作是不可打断的
}
public int Produce_Item() //产生放在模拟缓冲区中的一些数据
{
int tp=100;
Thread.Sleep(50);
return tp;
}
public void Consume_Item(int tp) //处理数据项
{
Thread.Sleep(50);
}
public void Producer() //生产者
{
int item=0;
while(true)
{
item=Produce_Item();
Down(ref empty);
mutex.WaitOne();
Insert_Item(item);
mutex.ReleaseMutex();
Up(ref full);
}
}
public void Consumer() //消费者
{
int item=0;
while(true)
{
Down(ref full);
mutex.WaitOne();
item=Remove_Item();
mutex.ReleaseMutex();
Up(ref empty);
Consume_Item(item);
}
}
/// <summary>
/// 应用程序的主入口点。
/// </summary>
//[STAThread]
static void Main(string[] args)
{
int i=0,j=0;
mutex=new Mutex(false,"MUTEX");
Producer_Consumer e = new Producer_Consumer();
ThreadStart ps = new ThreadStart(e.Producer);
Thread p = new Thread(ps);
p.Start(); //启动生产者线程
ThreadStart cs = new ThreadStart(e.Consumer);
Thread c = new Thread(cs);
c.Start(); //启动消费者线程
while(true)
{
j=full;
if(i!=j) //缓冲区改变时输出缓冲区状态
{
Console.WriteLine(j.ToString());
i=j;
}
}
Console.ReadLine();
}
}
}
//by BodeSmile
using System;
using System.Threading;
namespace Producer_Consumer
{
class Producer_Consumer
{
public const int N = 100; //缓冲区中的槽数目
public static Mutex mutex; //控制对临界区的访问
public static int empty = N; //计数缓冲区的空槽数目
public static int full = 0; //计数缓冲区的满槽数目
public static int [] buffer = new int[N]; //模拟缓冲区
public static int cnt=0; //记录模拟缓冲区的起始位置
public void Insert_Item(int tp) //将(新)数据项放入缓冲区中
{
buffer[(cnt+full)%N]=tp;
}
public int Remove_Item() //将(新)数据项放入缓冲区中
{
int tp=buffer[cnt];
cnt=(cnt+1)%N;
return tp;
}
public void Down(ref int tp)
{
Monitor.Enter(this); //以下操作是不可打断的
while(tp<=0)
{
Monitor.Pulse(this);
Monitor.Wait(this);
}
tp--;
Monitor.Exit(this); //以上操作是不可打断的
}
public void Up(ref int tp)
{
Monitor.Enter(this); //以下操作是不可打断的
tp++;
Monitor.Exit(this); //以上操作是不可打断的
}
public int Produce_Item() //产生放在模拟缓冲区中的一些数据
{
int tp=100;
Thread.Sleep(50);
return tp;
}
public void Consume_Item(int tp) //处理数据项
{
Thread.Sleep(50);
}
public void Producer() //生产者
{
int item=0;
while(true)
{
item=Produce_Item();
Down(ref empty);
mutex.WaitOne();
Insert_Item(item);
mutex.ReleaseMutex();
Up(ref full);
}
}
public void Consumer() //消费者
{
int item=0;
while(true)
{
Down(ref full);
mutex.WaitOne();
item=Remove_Item();
mutex.ReleaseMutex();
Up(ref empty);
Consume_Item(item);
}
}
/// <summary>
/// 应用程序的主入口点。
/// </summary>
//[STAThread]
static void Main(string[] args)
{
int i=0,j=0;
mutex=new Mutex(false,"MUTEX");
Producer_Consumer e = new Producer_Consumer();
ThreadStart ps = new ThreadStart(e.Producer);
Thread p = new Thread(ps);
p.Start(); //启动生产者线程
ThreadStart cs = new ThreadStart(e.Consumer);
Thread c = new Thread(cs);
c.Start(); //启动消费者线程
while(true)
{
j=full;
if(i!=j) //缓冲区改变时输出缓冲区状态
{
Console.WriteLine(j.ToString());
i=j;
}
}
Console.ReadLine();
}
}
}
最后再放上完成图形界面后的一张效果图,呵呵!