Can someone help me break down my assignment

I am having a trouble just breaking down this big assignment. I have code done, want someone to tell me if I am on the right track Here is my assignment:
1. Create a structure Coin and a class Purse.
A coin has a name and monetary value. Choose your way to implement a coin, but provide a way to check that two coins have equal names and monetary values.
A purse holds a collection of coins. Make a Purse constructor to construct an empty purse and the following methods of the class Purse:
a. Add a number of instances of a coin to the purse. Parameters: the coin to add and how many of it.
b. Count the number of coins in the purse that match a given coin. Parameter: the coin to match. Return value: the number of coins equal to the coin to match.
c. Get the total value of the coins in the purse. Return the sum of all coin values.
d. Count the number of coins in the purse. Return the number of coins.

2. Create a console application in which the main function will initialize an array of 10 purses and will start 10 threads working simultaneously with these purses without causing inconsistent states. Initially set up the purses with the same coins in each purse. The main function will wait for all threads to finish and then finish itself.
3. Each of the threads should have its own purse, from which it will take money and place in other purses. For this purpose it will repeatedly select a target purse at random and coins to move in the target purse. If the needed coins are not available at the moment, it should wait until they become available and do the move. Since the move of coins from one purse to another involves taking the coins out of one purse and putting them in another purse, each time select at random which operation to do first, and have a small delay between the operations, to allow for race conditions. From time to time each thread will sum up the coins of each denomination in all purses. Pay attention to the readability of the program output. If the threads are properly synchronized, the total number of coins of each denomination should be constant.
4. Provide synchronization using locks. Clearly identify with comments the points in the programs at which you obtain and release the locks, so that it is easy to find these points and test the programs with and without synchronization.
5. Test your programs with and without synchronization and note the results in the test report. Reason about the possibility of your synchronized programs to create deadlocks. If your analysis shows the possibility of a deadlock, provide test cases that could lead to deadlocks and note the results in the test report. Then change the necessary settings (initial coins, maximum numbers to move, associations between threads and purses, etc. to create a program in which a deadlock cannot occur. If your analysis shows that deadlock is impossible, change the original settings to be able to illustrate deadlocks, record the changes in the test report, and provide test cases that can lead to a deadlock. In all cases record your reasoning, the experiments, the expected and the actual results in the test report. Provide the source code before and after the changes.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//purseTest.cpp 
using namespace System;
#include "Purse.h"
int main()	{	
	Purse^ myPurse = gcnew Purse();

	Thread^ addNickels = gcnew Thread(gcnew ParameterizedThreadStart(myPurse, &Purse::addNickels));
	Thread^ addQuarters = gcnew Thread(gcnew ParameterizedThreadStart(myPurse, &Purse::addQuarters));
	Thread^ remove = gcnew Thread(gcnew ParameterizedThreadStart(myPurse, &Purse::removeCoin));
	Thread^ count = gcnew Thread(gcnew ThreadStart(myPurse, &Purse::getTotal));
	int^ nickles = 5;
	double^ size = .05;
	addNickels->Start(dynamic_cast<Object^>(nickles));
	addQuarters->Start(dynamic_cast<Object^>(nickles));
	remove->Start(dynamic_cast<Object^>(size));
	count->Start();
	count = gcnew Thread(gcnew ThreadStart(myPurse, &Purse::getTotal));
	Thread::Sleep(200);
	count->Start();
	Console::ReadLine();
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
//purse.h
using namespace System;
using namespace System::Threading;

ref class Purse
{
public:
	/**
	Constructs an empty purse.
	*/
	Purse();

	/**
	Add nickels to the purse.
	@param count the number of nickels to add
	*/
	void addNickels(Object^ count);
	
	/**
	Add dimes to the purse.
	@param count the number of dimes to add
	*/
	void addDimes(Object^ count);
	

	/**
	Add quarters to the purse.
	@param count the number of quarters to add
	*/
	void addQuarters(Object^ count);

	//removes one coin of the specifed denomination
	void removeCoin(Object^ count);
	

	/**
	Get the total value of the coins in the purse.
	@return the sum of all coin values
	*/
	void getTotal();

	

private:
	static const double NICKEL_VALUE = 0.05;
	static const double DIME_VALUE = 0.1;
	static const double QUARTER_VALUE = 0.25;

	int nickels;
	int dimes;
	int quarters;

};//ref class Purse 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
//purse.cpp
using namespace System;
#include "Purse.h"
#include <random>

/**
Constructs an empty purse.
*/
Purse::Purse()
{
	nickels = 0;
	dimes = 0;
	quarters = 0;
}

/**
Add nickels to the purse.
@param count the number of nickels to add
*/
void Purse::addNickels(Object^ count)
{
	for (int i = 1; i <= static_cast<int>(count); i++){
		Monitor::Enter(this);
		nickels = nickels += 1;
		Console::WriteLine("{0} nickles added",i);
		Thread::Sleep(rand() % 20);
		Monitor::Exit(this);
	}
}

/**
Add dimes to the purse.
@param count the number of dimes to add
*/
void Purse::addDimes(Object^ count){
	for (int i = 1; i <= static_cast<int>(count); i++){
		Monitor::Enter(this);
		dimes = dimes += 1;
		Console::WriteLine("{0} dimes added", i);
		Thread::Sleep(rand() % 20);
		Monitor::Exit(this);
	}
}

/**
Add quarters to the purse.
@param count the number of quarters to add
*/
void Purse::addQuarters(Object^ count)
{
	for (int i = 1; i <= static_cast<int>(count); i++){
		Monitor::Enter(this);
		quarters += 1;
		Console::WriteLine("{0} Quarters added", i);
		Thread::Sleep(rand() % 20);
		Monitor::Exit(this);
	}
}


void Purse::removeCoin(Object^ val){
	if (static_cast<double>(val) == NICKEL_VALUE){
		Monitor::Enter(this);
		nickels -= 1;
		Console::WriteLine("nickle removed");
		Thread::Sleep(rand() % 20);
		Monitor::Exit(this);
		
	}
	else if (static_cast<double>(val) == DIME_VALUE){
		Monitor::Enter(this);
		dimes -= 1;
		Console::WriteLine("dime removed");
		Thread::Sleep(rand() % 20);
		Monitor::Exit(this);
		
	}
	else if (static_cast<double>(val) == QUARTER_VALUE){
		Monitor::Enter(this);
		quarters -= 1;
		Console::WriteLine("quarter removed");
		Thread::Sleep(rand() % 20);
		Monitor::Exit(this);
		
	}
	else{
		Console::WriteLine("not a valid donomination");
	}
}

/**
Get the total value of the coins in the purse.
@return the sum of all coin values
*/
void Purse::getTotal()
{
	double total = 0;
	Monitor::Enter(this);
	total += nickels* NICKEL_VALUE;
	total += dimes* DIME_VALUE;
	total += quarters* QUARTER_VALUE;
	Thread::Sleep(rand() % 20);
	Console::WriteLine("{0} is the total amount", total);
	Monitor::Exit(this);
}
Last edited on
I don't want to continue working if I am not on the right track, please guide me someone
How should be know if you're on the right track? You haven't posted any code or even a description of what you're doing.

Reading through the assignment, most of the hard stuff is in the multi-threaded nature. One thing that really stands out to me is
If the threads are properly synchronized, the total number of coins of each denomination should be constant.
That means that moving coins from one purse to another must be completely atomic. You could do this by having a single mutex that all threads must lock to do a transfer. That basically makes the program single-threaded (bad for performance). However, the program is still non-deterministic, meaning that it runs in an undetermined order.

The more I think about it, the more I think you have to do it this way. I can't think of a way to get a snapshot of the total value of coins in all purses without locking the entire monetary system.

Start by getting the Coin and Purse classes working. You can do this with a single threaded program to test them.

Each thread takes a purse as its argument. This is the source purse. So the thread removes coins from that purse and puts them in another random (and different) one.

Create some pseudo code for how each thread should manage the synchronization. YOu need to think and design the solution before you start writing code.

Make a small wrapper for your locking and unlocking so that you can disable it for part 5.

This strikes me as one of the more complex problems that have appeared on this forum. Allow yourself plenty of time to write the code.
I posted my code
I don't recognize some of your syntax:
Thread^ addNickels = ...
If you want a pointer, the syntax is Thread*. But why use a pointer at all? Just create the thread as a local variable.

You don't appear to have created struct Coin.
A purse holds a collection of coins.

So the data in a purse should be something sort of collection involving Coins. Since a purse can hold multiple coins of the same type, I'd consider:
map<Coin, unsigned> coins; // maps coin to the number of coins of that time in the purse
the main function will initialize an array of 10 purses and will start 10 threads

I don't see 10 purses or 10 threads. You have created threads to add/remove coins where each thread deals with a specific type of coin. You're supposed to have 10 threads where each thread manages a particular purse.

a. Add a number of instances of a coin to the purse. Parameters: the coin to add and how many of it.

So class Purse should have something like addCoins(Coin &kind, int numToAdd);. If you allow numToAdd() to be positive or negative then this will handle removing coins also.

b. Count the number of coins in the purse that match a given coin. Parameter: the coin to match. Return value: the number of coins equal to the coin to match.

So something like unsigned numCoins(Coin &kind);

c. Get the total value of the coins in the purse. Return the sum of all coin values.

Your getTotal() should return int, not void. Also, see below.

d. Count the number of coins in the purse. Return the number of coins.

This might be called getTotal() also, but we already have that. Hmm. How to distinguish these two? Maybe use getNumCoins() to return the total number of coins and getValue() to return the total value of all the coins.

As I said before, write the Coin and Purse classes first and test them. Then add the threading logic.
@dhayden,
he's using C++ for .NET.
Thread^ is a handle to a managed (i.e. garbage collected) class.

@anon001,
I don't know much about multi-threaded programming so I can't help, but have a look here.
http://www.drdobbs.com/cpp/ccli-threading-part-i/184402018
or try
http://www.dreamincode.net/forums/forum/145-cli-c/
thank you @Thomas1965
Topic archived. No new replies allowed.