C#Learner12 Ответов: 2

Методы синхронизации C# и многопоточность


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:


Что я уже пробовал:

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

    }
}
}

honey the codewitch

Я не буду публиковать это в качестве ответа, потому что это не так, но вам будет гораздо проще использовать задачи вместо потоков. Тогда вы можете просто ждать их

C#Learner12

Я согласен, но меня попросили использовать темы, а не задачи. Я не очень хорошо разбираюсь в нитях, этот вопрос поставил меня в тупик

honey the codewitch

Вы должны использовать объект ManualResetEvent для запуска, когда поток будет завершен. сделайте другой для каждого потока. Когда вам нужно подождать, позвоните Уэйтхэндлу.WaitAll() и передайте все это, если ваши объекты ManualResetEvent. Вы устанавливаете один из них с помощью Set(). Если вы сделаете WaitAll (), он будет ждать, пока все они не будут установлены.

Richard Deeming

ArrayList это древний класс, который не должен использоваться ни в одном коде, написанном в течение последних 14 лет. Вы действительно должны использовать System.Collections.Generic.List<Coin>, или какая-то другая общая коллекция.

То GetValue и GetName методы на Coin класс действительно должен быть свойствами. С помощью Get* методы, когда вы не делаете никакой сложной логики, больше похожи на Java.

Вам также не хватает блокировки внутри вашего устройства. Purse.GetTotal метод - все остальное, что имеет доступ к coins поле потокобезопасно, но этот метод-нет.

honey the codewitch

Ричард, я согласен с тобой, и я предполагаю, что его профессор кормит его .NET 1измами. И меня нисколько не удивляет, что это такое явальское имя, если оно выходит из школы. Похоже, что все эти кошки имеют дело с Явой, даже если они болтают на другом языке.

2 Ответов

Рейтинг:
19

honey the codewitch

Здесь. Я дам вам шаблон о том, как использовать ManualResetEvent, чтобы получить то, что вы хотите.
Отрегулируйте это для вашего кода.

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


Надеюсь, это поможет! Заменить Нить.Спите(x) с вашей реальной работой

Отредактировано для добавления: помните, что ваш производственный код должен использовать Task или по крайней мере ThreadPool.QueueUserWorkItem() по возможности. С помощью Thread это не рекомендуется, несмотря на то, что ваш профессор учит вас. Просто совет на будущее. Большинство вещей, которым они учат в школе, не готовы к производству =(. Если бы это было так.


BillWoodruff

+5

Maciej Los

5ed!

honey the codewitch

Спасибо ребята =)

Рейтинг:
0

C#Learner12

не очень помогает мне, не понимая, как я могу заставить это работать в моей основной работе.

Richard MacCutchan

Вы должны изучить его и подумать о том, что вы пытаетесь сделать. Разработка - это не просто копирование кода из интернета.