C#监视器/信号量并发为缓冲区生成使用者
我正在解决一个典型的生产者-消费者问题。我有多个生产者和一个消费者。有n个生产者线程,每个线程调用SetOne(orderobjectorder),消费者调用GetOne()。Buffer类用作包含C#监视器/信号量并发为缓冲区生成使用者,c#,multithreading,monitor,C#,Multithreading,Monitor,我正在解决一个典型的生产者-消费者问题。我有多个生产者和一个消费者。有n个生产者线程,每个线程调用SetOne(orderobjectorder),消费者调用GetOne()。Buffer类用作包含
public class Buffer
{
public static OrderObject[] BufferCells;
public static Semaphore _pool { get; set; }
public static void SetOne(OrderObject order)
{
_pool.WaitOne();
try
{
Monitor.Enter(BufferCells);
for (int i = 0; i < BufferCells.Length - 1; i++)
{
BufferCells[i] = order;
Console.WriteLine(String.Format("Client {0} Produced {1}", BufferCells[i].Id, BufferCells[i].Id));
}
}
finally
{
Monitor.Exit(BufferCells);
_pool.Release();
}
}
public static OrderObject GetOne()
{
_pool.WaitOne();
OrderObject value = null;
try
{
Monitor.Enter(BufferCells);
for (int i = 0; i < BufferCells.Length - 1; i++)
{
if (BufferCells[i].Id != "-1")
{
value = BufferCells[i];
BufferCells[i] = new OrderObject() { Id = "-1" }; /*Clear Cell*/
Console.WriteLine(String.Format(" Server Consumed {0}", value.Id));
break;
}
}
}
finally
{
Monitor.Exit(BufferCells);
_pool.Release();
}
return value;
}
}
public class Client
{
public int Id {get;set;}
public void Run()
{
/*Produce*/
Buffer.SetOne(Id);
}
}
public class Server
{
public void Run()
{
while(true)
{
Buffer.GetOne();
}
}
}
public class Program
{
public static void Main(string[] args)
{
/*Initialize 2 Open Semaphores*/
int numCells = 2;
Semaphore pool = new Semaphore(numCells, numCells);
/*Initialize BufferCells with Empty OrderObjects*/
List<OrderObject> OrderObjects = new List<OrderObject>();
for (var i = 0; i < numCells; i++)
{
OrderObjects.Add(new OrderObject() { Id = "-1" });
}
Buffer.BufferCells = OrderObjects.ToArray();
/*Initialize Consumer Thread*/
Server server = new Server(pool);
Thread serverThread = new Thread(new ThreadStart(server.Run));
/*Initialize Producer Objects*/
List<Client> clients = new List<Client>();
for (int i = 0; i <= 20; i++)
{
/*Create 5000 Clients*/
Client client = new Client(i.ToString(), pool, new OrderObject() { Id = i.ToString() });
clients.Add(client);
}
/*Start Each Client Thread*/
List<Thread> clientThreads = new List<Thread>();
foreach (var client in clients)
{
Thread t = new Thread(new ThreadStart(client.Run));
clientThreads.Add(t);
}
/*Start Server Thread*/
serverThread.Start();
/*Start Each Producer Thread*/
clientThreads.ForEach(p => p.Start());
/*Start Consumer Thread*/
Console.ReadLine();
}
}
公共类缓冲区
{
公共静态OrderObject[]缓冲单元;
公共静态信号量_池{get;set;}
公共静态void SetOne(OrderObject顺序)
{
_pool.WaitOne();
尝试
{
输入(缓冲单元格);
for(int i=0;i
我猜我遇到了以下问题之一:死锁、死锁或饥饿。由于某种原因,服务器无法使用生成并添加到单元格缓冲区的所有订单对象。不确定修复是什么。好的,让我们分解一下这段代码试图做什么
public class Buffer
{
public static OrderObject[] BufferCells;
public static Semaphore _pool { get; set; }
//一盘
//为什么这里需要信号灯
_pool.WaitOne();
try
{
//信号量是冗余的,因为Monitor.Enter是一个限制性更强的锁
Monitor.Enter(BufferCells);
//嗯?我以为这应该是赛特一号?不是所有的吗?我只能假设您的意图是设置其中一个单元格,而让其他单元格可用于设置或获取。如果您正试图实现这一点,那么队列似乎是更合适的数据结构。更好的是,还启用了锁定/阻塞机制
for (int i = 0; i < BufferCells.Length - 1; i++)
{
BufferCells[i] = order;
Console.WriteLine(String.Format("Client {0} Produced {1}", BufferCells[i].Id, BufferCells[i].Id));
}
}
finally
{
Monitor.Exit(BufferCells);
_pool.Release();
}
}
public static OrderObject GetOne()
{
//因为监视器也是一个限制性更强的锁
Monitor.Enter(BufferCells);
for (int i = 0; i < BufferCells.Length - 1; i++)
{
if (BufferCells[i].Id != "-1")
{
value = BufferCells[i];
BufferCells[i] = new OrderObject() { Id = "-1" }; /*Clear Cell*/
Console.WriteLine(String.Format(" Server Consumed {0}", value.Id));
break;
}
}
}
finally
{
Monitor.Exit(BufferCells);
_pool.Release();
}
return value;
}
}
Monitor.Enter(缓冲单元格);
for(int i=0;i
总而言之:
- 此代码使用冗余锁定,这是不必要的
- 此代码将缓冲区中的所有单元格一次性设置在独占锁下,这似乎首先破坏了缓冲区的用途
- 这段代码试图实现的功能似乎已经在中实现了。无需重新发明轮子!:)李>
祝你好运 我将假设监视器是为了保护对数组的访问,而信号量应该进行计数,是吗 如果是这样,则不应在getOne()的最后一节中调用“\u pool.Release()”,也不应在setOne()的顶部调用“\u pool.WaitOne()”。生产者的工作是在信号量推送对象之后发出信号,消费者的工作是在弹出对象之前等待信号量 啊 '使用的方法是首先将信号量初始化为所用缓冲区的相同大小,' 如果需要一个无边界队列,请将信号量初始化为0 如果你想要一个有界的q
_pool.WaitOne();
OrderObject value = null;
try
{
Monitor.Enter(BufferCells);
for (int i = 0; i < BufferCells.Length - 1; i++)
{
if (BufferCells[i].Id != "-1")
{
value = BufferCells[i];
BufferCells[i] = new OrderObject() { Id = "-1" }; /*Clear Cell*/
Console.WriteLine(String.Format(" Server Consumed {0}", value.Id));
break;
}
}
}
finally
{
Monitor.Exit(BufferCells);
_pool.Release();
}
return value;
}
}