Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/279.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C#监视器/信号量并发为缓冲区生成使用者_C#_Multithreading_Monitor - Fatal编程技术网

C#监视器/信号量并发为缓冲区生成使用者

C#监视器/信号量并发为缓冲区生成使用者,c#,multithreading,monitor,C#,Multithreading,Monitor,我正在解决一个典型的生产者-消费者问题。我有多个生产者和一个消费者。有n个生产者线程,每个线程调用SetOne(orderobjectorder),消费者调用GetOne()。Buffer类用作包含

我正在解决一个典型的生产者-消费者问题。我有多个生产者和一个消费者。有n个生产者线程,每个线程调用SetOne(orderobjectorder),消费者调用GetOne()。Buffer类用作包含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;
    }
 }