Threads never seem to get a chance, unless I have a breakpoint

I try to make a simple program that does the following:

I have two cranes that take containers off a ship. They put the containers on the quay, where 2/3 trucks pick them up. Cranes can put a maximum of 5 containers on the quay.

The problem is the following: when I don't have breakpoints, the crane threads just pick containers of the ship and put them onto the quay and then the program stops. This is the output every time:

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.

So, the truck threads do not run. When I put a breakpoint in Wagen.VoerWerkzaamhedenUit(), the breakpoint does get hit and miraculously the whole program runs till all containers have been processed.

Here's my code:

    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));
                }
            }
        }
    }

And no, I do not want to use a blocking collection, I want to use a List<int> ;-)

Upvotes: 1

Views: 99

Answers (2)

Jay
Jay

Reputation: 3355

Also learn about the Diagnostics namespace...

e.g.

if(!System.Diagnostics.Debugger.IsAttached)
    if(System.Diagnostics.Debugger.Attach()) System.Diagnostics.Debugger.Break();

Upvotes: 1

Eren Ers&#246;nmez
Eren Ers&#246;nmez

Reputation: 39085

When the program starts, the trucks check the quay (Kade.HeeftContainers()) before the cranes get a chance to put containers on the quay so the truck threads exit right away. Then the cranes continue filling up the quay until it reaches the limit of 5 containers. Since the truck threads already exited, the quay stays full so crane threads stop waiting on Monitor.Wait(containers);.

To resolve the issue, the trucks need to keep running until all the containers have gone through the pipeline. For example, you can have a counter on the quay (e.g. loadedContainers) and increment this counter everytime a container is removed from the quay to be loaded on the trucks. Then return loadedContainers == 100; in the Kade.HeeftContainers getter.

Upvotes: 1

Related Questions