It brokey

main
Oystein Kristoffer Tveit 2022-11-15 15:55:37 +01:00
parent 9c93da087d
commit fe79e3da4b
Signed by: oysteikt
GPG Key ID: 9F2F7D8250F35146
2 changed files with 69 additions and 45 deletions

View File

@ -2,8 +2,14 @@ class Bank(val allowedAttempts: Integer = 3) {
private val transactionsQueue: TransactionQueue = new TransactionQueue() private val transactionsQueue: TransactionQueue = new TransactionQueue()
private val processedTransactions: TransactionQueue = new TransactionQueue() private val processedTransactions: TransactionQueue = new TransactionQueue()
private var processingThreadsStarted = false;
private val processingThreads: List[Thread] =
(1 to 1).map(_ => new Thread {
override def run = processTransactions
}).toList
def addTransactionToQueue(from: Account, to: Account, amount: Double): Unit = { def addTransactionToQueue(from: Account, to: Account, amount: Double): Unit = {
printf("[%s]: Added transaction to queue\n", Thread.currentThread().toString())
transactionsQueue.push(new Transaction( transactionsQueue.push(new Transaction(
transactionsQueue, transactionsQueue,
processedTransactions, processedTransactions,
@ -13,36 +19,45 @@ class Bank(val allowedAttempts: Integer = 3) {
10, 10,
)) ))
Main.thread(processTransaction(transactionsQueue.pop())) if (!processingThreadsStarted) {
} processingThreads.foreach(t => {
// TODO t.start
// project task 2 print("Starting processing thread\n")
// create a new transaction object and put it in the queue })
// spawn a thread that calls processTransactions processingThreadsStarted = true;
// There are mixed instructions for this method.
// It's called `processTransactions`, indicating that it should
// process all lists, the part in the assigment pdf indicates this as well.
// However the comment below is written as if there is only one transaction to
// be processed, and the fact that `addTransactionToQueue` calls this method every
// time something is added, supports that theory as well.
// We just went with the most logical option...
private def processTransactions(trx: Transaction): Unit = {
// thread = Main.thread(trx)
// thread.join()
trx()
if (trx.status == TransactionStatus.PENDING && trx.attempt < trx.allowedAttemps) {
processTransactions(trx)
} else {
processedTransactions.push(trx);
} }
} }
// TODO // TODO
// project task 2 // project task 2
// Function that pops a transaction from the queue // create a new transaction object and put it in the queue
// and spawns a thread to execute the transaction. // spawn a thread that calls processTransactions
// Finally do the appropriate thing, depending on whether
// the transaction succeeded or not // This function is a worker that continuously
// pops elements from the queue and processes them.
// Multiple of these can be run on separate threads.
private def processTransactions: Unit = {
if (transactionsQueue.isEmpty) {
Thread.sleep(50)
} else {
val trx = transactionsQueue.pop
Main.thread(trx.run).join()
if (trx.status == TransactionStatus.PENDING) {
transactionsQueue.push(trx);
} else {
processedTransactions.push(trx);
}
}
processTransactions
}
// TODO
// project task 2
// Function that pops a transaction from the queue
// and spawns a thread to execute the transaction.
// Finally do the appropriate thing, depending on whether
// the transaction succeeded or not
def addAccount(initialBalance: Double): Account = { def addAccount(initialBalance: Double): Account = {
new Account(this, initialBalance) new Account(this, initialBalance)

View File

@ -16,16 +16,16 @@ class TransactionQueue {
def pop: Transaction = {queue.synchronized(queue.dequeue())} def pop: Transaction = {queue.synchronized(queue.dequeue())}
// Return whether the queue is empty // Return whether the queue is empty
def isEmpty: Boolean = {queue.synchronized(queue.isEmpty())} def isEmpty: Boolean = {queue.synchronized(queue.isEmpty)}
// Add new element to the back of the queue // Add new element to the back of the queue
def push(t: Transaction): Unit = {queue.synchronized(queue.push(t))} def push(t: Transaction): Unit = {queue.synchronized(queue.enqueue(t))}
// Return the first element from the queue without removing it // Return the first element from the queue without removing it
def peek: Transaction = {queue.synchronized(queue.front())} def peek: Transaction = {queue.synchronized(queue.front)}
// Return an iterator to allow you to iterate over the queue // Return an iterator to allow you to iterate over the queue
def iterator: Iterator[Transaction] = {queue.synchronized(queue.iterator())} def iterator: Iterator[Transaction] = {queue.synchronized(queue.iterator)}
} }
class Transaction(val transactionsQueue: TransactionQueue, class Transaction(val transactionsQueue: TransactionQueue,
@ -39,22 +39,31 @@ class Transaction(val transactionsQueue: TransactionQueue,
var attempt = 0 var attempt = 0
override def run: Unit = { override def run: Unit = {
def doTransaction(): Unit = {
def doTransaction() = {
// TODO - project task 3
// Extend this method to satisfy requirements.
from withdraw amount
to deposit amount
}
// TODO - project task 3 // TODO - project task 3
// make the code below thread safe // Extend this method to satisfy requirements.
if (status == TransactionStatus.PENDING) { if (from.withdraw(amount).isRight) {
doTransaction return
Thread.sleep(50) // you might want this to make more room for
// new transactions to be added to the queue
} }
if (to.deposit(amount).isRight) {
if (from.deposit(amount).isRight) print("oof")
return
}
status = TransactionStatus.SUCCESS
} }
attempt += 1
if (status != TransactionStatus.PENDING) {
return
}
from.synchronized(to.synchronized(doTransaction))
Thread.sleep(50)
if (attempt >= allowedAttemps) {
status = TransactionStatus.FAILED
}
}
} }