Click here to Skip to main content
15,867,686 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
So I started this question, I believe i have synchronized the methods correctly, need some insight on whats wrong and what should be done. I have to modify ths class Purse so that the method AddCoin is synchronized and implement a synchronized RemoveCoin method with a Coin argument, I believe that is done just fine. Where im really having trouble is implementing thread that adds pennies, another thread that adds quarters, and another thread that removes and prints randomly selected coins, pennies, quarters, any one. Then finally synchronize the threads to wait for each other when necessary. Here is what I have so far:


What I have tried:

Purse.cs

using System;
using System.Collections;
using System.Threading;

namespace TestingProject
{
    /// <summary>
    /// A purse holds a collection of coins.
    /// </summary>
public class Purse
{
    ///  Constructs an empty purse.
    public Purse()
    {
        coins = new ArrayList();

    }

    ///   Add a coin to the purse.
    ///   @param aCoin the coin to add
    public void Add(Coin aCoin)
    {
        Monitor.Enter(coins);
        coins.Add(aCoin);
        
        Monitor.Exit(coins);
    }
    public void RemoveCoin(Coin aCoin)
    {
        Monitor.Enter(coins);
        coins.Remove(aCoin);
        
        Monitor.Exit(coins);
    }
    

    ///  Get the total value of the coins in the purse.
    ///  @return the sum of all coin values
    public double GetTotal()
    {
        double total = 0;
        for (int i = 0; i < coins.Count; i++)
        {
            Coin aCoin = (Coin)coins[i];
            total = total + aCoin.GetValue();
        }
        return total;
    }

    private ArrayList coins;
}



}
Coin.cs

using System;
using System.Collections;

namespace TestingProject
{
    /// <summary>
    /// A coin with a monetary value.
    /// </summary>
public class Coin   {

    /// Constructs a coin.
    /// @param aValue the monetary value of the coin
    /// @param aName the name of the coin
    public Coin(double aValue, String aName) 
    { 
        value = aValue; 
        name = aName;
    }

    public Coin()
    {
    }

    /// Gets the coin value.
    /// @return the value
    public double GetValue()    
    {
        return value;
    }

    /// Gets the coin name.
    /// @return the name
    public String GetName() 
    {
        return name;
    }
    
    public override bool Equals(Object otherObject)
    {
        Coin other = (Coin)otherObject;
        return name==other.name
            && value == other.value;
    }

    // C# requirement: 
    // since we override Equals, MUST also override GetHashCode ( !! )
    public override int GetHashCode()
    {
        return base.GetHashCode ();
    }

    private double value;
    private string name;
}
}
pursetest.cs

using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.VisualBasic;


namespace TestingProject
{


class PurseTest
{
    public static void Main(string[] args)
    {
        

        // Random object used by each thread
        Random random = new Random();

        
        Purse purse =new Purse();

        Coin coin = new Coin();

        // output column heads and initial buffer state
        Console.WriteLine("{0,-35}{1,-9}{2}\n",
           "Operation", "Buffer", "Occupied Count");


        
        Thread purseThread =
           new Thread(new ThreadStart(purse.Add))
           {
               Name = "Purse"
           };

        Thread coinThread =
           new Thread(new ThreadStart(coin.GetValue));
        coinThread.Name = "coin";

        // start each thread
        purseThread.Start();
        coinThread.Start();

    }
}
}
Posted
Updated 3-Aug-20 10:49am
v2
Comments
honey the codewitch 3-Aug-20 15:13pm    
I won't post this as an answer, because it's not, but you'd have a much easier time I think using Tasks instead of threads. Then you can just await them
C#Learner12 3-Aug-20 15:18pm    
I agree, but i was asked to use threads not tasks. I am not good at threads, this question has stumped me
honey the codewitch 3-Aug-20 15:40pm    
You should use a ManualResetEvent object to trigger when the thread is done. do a different one for each thread. When you need to wait call WaitHandle.WaitAll() and pass it all if your ManualResetEvent objects. You set one of those with Set(). If you do WaitAll() it will wait until they are all set.
Richard Deeming 4-Aug-20 12:34pm    
ArrayList is an ancient class which shouldn't be used in any code written within the last 14 years. You should really be using System.Collections.Generic.List<Coin>, or some other generic collection.

The GetValue and GetName methods on the Coin class should really be properties. Using Get* methods when you're not doing any complicated logic looks more like Java.

You're also missing the locking within your Purse.GetTotal method - everything else which access the coins field is thread-safe, but this method isn't.
honey the codewitch 5-Aug-20 11:26am    
Richard, I agree with you and I'm guessing his prof is feeding him .NET 1isms. And it doesn't surprise me that it's javalike naming if it's coming out of a school. Seems like all those cats deal in is java, even if they're mucking about in a different language.

Here. I'll give you a boilerplate on how to use ManualResetEvent to get what you want.
Adjust this for your code.

C#
static void Main(string[] args)
{
	// to signal completion
	ManualResetEvent event1 = new ManualResetEvent(false);
	ManualResetEvent event2 = new ManualResetEvent(false);
	ManualResetEvent event3 = new ManualResetEvent(false);
	// try/finally so we always Dispose(), even on error
	try
	{
		// create threads
		Thread thread1 = new Thread(new ParameterizedThreadStart(Start1));
		Thread thread2 = new Thread(new ParameterizedThreadStart(Start2));
		Thread thread3 = new Thread(new ParameterizedThreadStart(Start3));
		// start them, passing the events
		thread1.Start(event1);
		thread2.Start(event2);
		thread3.Start(event3);
		// wait for all of them to complete
		WaitHandle.WaitAll(new WaitHandle[] { event1, event2, event3 });
		Console.WriteLine("Done!");
	}
	finally
	{
		// clean up
		event1.Dispose();
		event2.Dispose();
		event3.Dispose();
	}
			
}
static void Start1(object waitHandle)
{
	// do work here:
	Thread.Sleep(300);
	Console.WriteLine("Start1 complete");
	((ManualResetEvent)waitHandle).Set();
}
static void Start2(object waitHandle)
{
	// do work here:
	Thread.Sleep(500);
	Console.WriteLine("Start2 complete");
	((ManualResetEvent)waitHandle).Set();
}
static void Start3(object waitHandle)
{
	// do work here:
	Thread.Sleep(100);
	Console.WriteLine("Start 3 complete");
	((ManualResetEvent)waitHandle).Set();
}


I hope that helps! Replace Thread.Sleep(x) with your actual work

Edited to add: Remember that your production code should be using Task or at least ThreadPool.QueueUserWorkItem() whenever possible. Using Thread isn't recommended despite what your prof is teaching you. Just a tip for down the road. Most of the stuff they teach in school isn't production ready =(. I wish it was.
 
Share this answer
 
v2
Comments
BillWoodruff 3-Aug-20 18:35pm    
+5
Maciej Los 4-Aug-20 2:21am    
5ed!
honey the codewitch 4-Aug-20 11:15am    
Thanks folks =)
 
Share this answer
 
Comments
C#Learner12 3-Aug-20 16:22pm    
not helping me that much, not understanding how i can make this work in my main
Richard MacCutchan 3-Aug-20 16:23pm    
You have to study it and think about what you are trying to do. Development is not just a matter of copying code from the internet.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900