1

次のことを行う簡単なプログラムを作成しようとしています。

コンテナを船から降ろすクレーンが 2 台あります。彼らはコンテナを波止場に置き、そこで 2/3 のトラックがコンテナをピックアップします。クレーンは岸壁に最大 5 個のコンテナを配置できます。

問題は次のとおりです。ブレークポイントがない場合、クレーン スレッドは船のコンテナを選択して埠頭に置くだけで、プログラムが停止します。これは毎回の出力です:

Kraan 2 heeft container nummer 1 van het schip gehaald.
Kraan 2 heeft container nummer 1 op de kade geplaatst.
Kraan 1 heeft container nummer 2 van het schip gehaald.
Kraan 1 heeft container nummer 2 op de kade geplaatst.
Kraan 2 heeft container nummer 3 van het schip gehaald.
Kraan 1 heeft container nummer 4 van het schip gehaald.
Kraan 2 heeft container nummer 3 op de kade geplaatst.
Kraan 2 heeft container nummer 5 van het schip gehaald.
Kraan 2 heeft container nummer 5 op de kade geplaatst.
Kraan 1 heeft container nummer 4 op de kade geplaatst.
Kraan 2 heeft container nummer 6 van het schip gehaald.
Kraan 1 heeft container nummer 7 van het schip gehaald.

そのため、トラック スレッドは実行されません。Wagen.VoerWerkzaamhedenUit() にブレークポイントを設定すると、ブレークポイントヒットし、奇跡的にすべてのコンテナーが処理されるまでプログラム全体が実行されます。

これが私のコードです:

    class Program
    {
        static void Main(string[] args)
        {
            for (int i = 1; i <= 100; i++)
            {
                Schip.LaadContainerOpSchip(i);
            }

            Thread kraan1 = new Thread(new Kraan().VoerWerkzaamhedenUit);
            kraan1.Name = "Kraan 1";
            kraan1.Start();

            Thread kraan2 = new Thread(new Kraan().VoerWerkzaamhedenUit);
            kraan2.Name = "Kraan 2";
            kraan2.Start();

            Thread wagen1 = new Thread(new Wagen().VoerWerkzaamhedenUit);
            wagen1.Name = "Wagen 1";
            wagen1.Start();

            Thread wagen2 = new Thread(new Wagen().VoerWerkzaamhedenUit);
            wagen2.Name = "Wagen 2";
            wagen2.Start();

            kraan1.Join();
            kraan2.Join();
            wagen1.Join();
            wagen2.Join();

            Console.WriteLine("Press any key to continue...");
            Console.Read();
        }
    }

public class Kraan
    {
        private Random random = new Random();

        public void VoerWerkzaamhedenUit()
        {
            while (Schip.HeeftContainers())
            {
                Thread.Sleep(random.Next(1000, 6000));

                int container = Schip.VerwijderContainer();

                if (container != -1)
                {
                    Console.WriteLine("{0} heeft container nummer {1} van het schip gehaald.", Thread.CurrentThread.Name, container);

                    Thread.Sleep(random.Next(1000, 6000));

                    Kade.PlaatsContainer(container);

                    Console.WriteLine("{0} heeft container nummer {1} op de kade geplaatst.", Thread.CurrentThread.Name, container);
                }
            }
        }
    }

public static class Schip
    {
        private static List<int> containers = new List<int>();

        public static void LaadContainerOpSchip(int container)
        {
            containers.Add(container);
        }

        public static int VerwijderContainer()
        {
            lock (containers)
            {
                int container = -1;

                if (containers.Any())
                {
                    container = containers[0];

                    containers.RemoveAt(0);
                }

                return container;
            }
        }

        public static bool HeeftContainers()
        {
            lock (containers)
            {
                return containers.Any();
            }
        }
    }



public static class Kade
    {
        private static List<int> containers = new List<int>();

        public static void PlaatsContainer(int container)
        {
            lock (containers)
            {
                while (containers.Count == 5)
                {
                    Monitor.Wait(containers);
                }

                containers.Add(container);

                Monitor.PulseAll(containers);
            }
        }

        public static int VerwijderContainer()
        {    
            lock (containers)
            {
                while (containers.Count == 0)
                {
                    Monitor.Wait(containers);
                }

                int container = -1;

                if (containers.Any())
                {
                    container = containers[0];

                    containers.RemoveAt(0);
                }

                Monitor.PulseAll(containers);

                return container;
            }
        }

        public static bool HeeftContainers()
        {
            lock (containers)
            {
                return containers.Any();
            }
        }
    }

public class Wagen
    {
        private Random random = new Random();

        public void VoerWerkzaamhedenUit()
        {
            while (Kade.HeeftContainers())
            {
                Thread.Sleep(random.Next(1000, 6000));

                int container = Kade.VerwijderContainer();

                if (container != -1)
                {
                    Console.WriteLine("{0} heeft container nummer {1} van de kade gehaald.", Thread.CurrentThread.Name, container);

                    Thread.Sleep(random.Next(1000, 6000));
                }
            }
        }
    }

いいえ、ブロッキング コレクションを使用したくありませんList<int>。使用したい;-)

4

2 に答える 2

1

Kade.HeeftContainers()プログラムが開始されると、クレーンがコンテナーを岸壁に載せる前に、トラックが岸壁をチェックします ( )。その後、コンテナ 5 個の制限に達するまで、クレーンは岸壁を埋め続けます。トラックのスレッドはすでに出ているため、岸壁は満員のままで、クレーンのスレッドは待機を停止しMonitor.Wait(containers);ます。

この問題を解決するには、すべてのコンテナがパイプラインを通過するまでトラックを動かし続ける必要があります。たとえば、埠頭にカウンターを設置し (例: loadedContainers)、コンテナーが埠頭から移動してトラックに積み込まれるたびに、このカウンターをインクリメントできます。次にreturn loadedContainers == 100;Kade.HeeftContainersゲッターで。

于 2012-05-19T10:58:24.650 に答える
1

また、Diagnostics 名前空間についても学びます...

例えば

if(!System.Diagnostics.Debugger.IsAttached)
    if(System.Diagnostics.Debugger.Attach()) System.Diagnostics.Debugger.Break();
于 2012-05-19T12:17:37.000 に答える