diff --git a/.clang-format b/.clang-format deleted file mode 100644 index 941486e..0000000 --- a/.clang-format +++ /dev/null @@ -1,3 +0,0 @@ ---- -BasedOnStyle: LLVM ---- diff --git a/.gitignore b/.gitignore index e5e3700..3d8789c 100644 --- a/.gitignore +++ b/.gitignore @@ -54,15 +54,6 @@ dkms.conf # debug information files *.dwo -# LaTeX -.auctex-auto/ -*.fls -*.log -*.synctex.gz -*.fdb_latexmk -*.aux -*.pdf - # Nix related things .direnv/ result*/ diff --git a/assignment1/default.nix b/assignment1/default.nix index 54b1f8b..293fb6b 100644 --- a/assignment1/default.nix +++ b/assignment1/default.nix @@ -1,22 +1,22 @@ let - basicC = name: { stdenv }: + basic-c = name: { stdenv }: stdenv.mkDerivation { inherit name; src = ./.; buildPhase = '' runHook preBuild - gcc part2/${name}.c -o ${name}.bin + gcc part2/${name}.c -o ${name} runHook postBuild ''; installPhase = '' runHook preInstall mkdir -p $out/bin - install ${name}.bin $out/bin/${name} + install ${name} $out/bin/ runHook postInstall ''; }; in { - a1-hello = basicC "hello"; - a1-employee = basicC "employee"; - a1-logwriter = basicC "logwriter"; + a1-hello = basic-c "hello"; + a1-employee = basic-c "employee"; + a1-logwriter = basic-c "logwriter"; } diff --git a/assignment2/default.nix b/assignment2/default.nix index d63155d..7f9f5b6 100644 --- a/assignment2/default.nix +++ b/assignment2/default.nix @@ -1,26 +1,26 @@ let - basicC = subdir: name: { stdenv }: + basic-c = subdir: name: { stdenv }: stdenv.mkDerivation { inherit name; src = ./.; buildPhase = '' runHook preBuild - gcc ${subdir}/${name}.c -o ${name}.bin + gcc ${subdir}/${name}.c -o ${name} runHook postBuild ''; installPhase = '' runHook preInstall mkdir -p $out/bin - install ${name}.bin $out/bin/${name} + install ${name} $out/bin/ runHook postInstall ''; }; in { - a2-p1-producer = basicC "part1" "producer"; - a2-p1-consumer = basicC "part1" "consumer"; + a2-p1-producer = basic-c "part1" "producer"; + a2-p1-consumer = basic-c "part1" "consumer"; - a2-p2-bidirectional = basicC "part2" "bidirectional"; + a2-p2-bidirectional = basic-c "part2" "bidirectional"; - a2-p3-producer = basicC "part3" "producer"; - a2-p3-consumer = basicC "part3" "consumer"; + a2-p3-producer = basic-c "part3" "producer"; + a2-p3-consumer = basic-c "part3" "consumer"; } diff --git a/flake.nix b/flake.nix index dd5848a..03d2962 100644 --- a/flake.nix +++ b/flake.nix @@ -11,7 +11,6 @@ subdirs = [ "assignment1" "assignment2" - "project1" ]; eachSystem = nixpkgs.lib.genAttrs (import systems); diff --git a/project1/README.md b/project1/README.md deleted file mode 100644 index 1d06267..0000000 --- a/project1/README.md +++ /dev/null @@ -1,25 +0,0 @@ -# CS3502 Project 1: Asynchronous Banking Account Management - -This directory contains multiple toy models of asynchronous bank account systems, demonstrating the principles of race condition and deadlock avoidance. - -## Usage - -There are 4 programs labeled Phases 1-4: - -- **Phase 1**: Naive non-supervised multi-threaded account system -- **Phase 2**: Mutex-based account system -- **Phase 3**: Deadlock generation -- **Phase 4**: Deadlock resolution via lock ordering - -If you have [Nix](https://nixos.org/) installed: - -```sh -nix run .#p1-phase1 -``` - -Otherwise, the code must be compiled manually: - -``` sh -gcc phase1/phase1.c -o phase1.bin -``` - diff --git a/project1/default.nix b/project1/default.nix deleted file mode 100644 index dffb073..0000000 --- a/project1/default.nix +++ /dev/null @@ -1,23 +0,0 @@ -let - basicC = subdir: name: { stdenv }: - stdenv.mkDerivation { - inherit name; - src = ./.; - buildPhase = '' - runHook preBuild - gcc ${subdir}/${name}.c -o ${name}.bin - runHook postBuild - ''; - installPhase = '' - runHook preInstall - mkdir -p $out/bin - install ${name}.bin $out/bin/${name} - runHook postInstall - ''; - }; -in { - p1-phase1 = basicC "phase1" "phase1"; - p1-phase2 = basicC "phase2" "phase2"; - p1-phase3 = basicC "phase3" "phase3"; - p1-phase4 = basicC "phase4" "phase4"; -} diff --git a/project1/phase1/output.png b/project1/phase1/output.png deleted file mode 100644 index e2f0d62..0000000 Binary files a/project1/phase1/output.png and /dev/null differ diff --git a/project1/phase1/phase1.c b/project1/phase1/phase1.c deleted file mode 100644 index d49d859..0000000 --- a/project1/phase1/phase1.c +++ /dev/null @@ -1,107 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -#define NUM_ACCOUNTS 8 -#define NUM_TELLERS 128 -#define TRANSACTIONS_PER_TELLER 100 - -// Monetary value in cents -typedef long currency; - -void printf_currency(currency c) { - if (c < 0) { - c = -c; - printf("-"); - } - printf("$%ld.%.2ld", c / 100, c % 100); -} - -// Accounts (shared resource) -typedef struct account { - int account_id; - currency balance; - int transaction_count; -} account; - -// Global account array -account accounts[NUM_ACCOUNTS]; - -// Teller threads - -pthread_t tellers[NUM_TELLERS]; - -typedef struct teller_args { - int teller_id; - currency total; -} teller_args; - -void *teller_thread(void *arg) { - teller_args *args = (teller_args *)arg; - int id = args->teller_id; - currency total = 0; - - unsigned int seed = time(NULL) + pthread_self(); - for (int i = 0; i < TRANSACTIONS_PER_TELLER; i++) { - printf("Thread %u: ", id); - // Deposit or withdraw random currency amount from $0 to $1000 - currency random_amount = ((long)rand_r(&seed)) % 100000; - if (rand_r(&seed) % 2) { - printf("Withdrawing "); - printf_currency(random_amount); - random_amount = -random_amount; - } else { - printf("Depositing "); - printf_currency(random_amount); - } - - int random_acc = rand_r(&seed) % NUM_ACCOUNTS; - accounts[random_acc].balance += random_amount; - accounts[random_acc].transaction_count++; - - printf(" into account %u\n", random_acc); - - total += random_amount; - } - - args->total = total; - return NULL; -} - -int main() { - // Initialize all accounts with 0 balance - for (int i = 0; i < NUM_ACCOUNTS; i++) { - accounts[i] = (account){.account_id = i, .balance = 0}; - } - - // Initialize tellers - teller_args args[NUM_TELLERS]; - for (int i = 0; i < NUM_TELLERS; i++) { - args[i] = (teller_args){.teller_id = i}; - pthread_create(&tellers[i], NULL, teller_thread, &args[i]); - } - - // Wait for all threads to finish - currency expected_total = 0; - for (int i = 0; i < NUM_TELLERS; i++) { - pthread_join(tellers[i], NULL); - expected_total += args[i].total; - } - - currency actual_total = 0; - for (int i = 0; i < NUM_ACCOUNTS; i++) { - actual_total += accounts[i].balance; - } - - printf("Total balance: "); - printf_currency(actual_total); - printf("\nExpected total: "); - printf_currency(expected_total); - printf("\n"); - - return 0; -} diff --git a/project1/phase2/output.png b/project1/phase2/output.png deleted file mode 100644 index 0d67ee1..0000000 Binary files a/project1/phase2/output.png and /dev/null differ diff --git a/project1/phase2/phase2.c b/project1/phase2/phase2.c deleted file mode 100644 index 9c4911c..0000000 --- a/project1/phase2/phase2.c +++ /dev/null @@ -1,130 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -#define NUM_ACCOUNTS 8 -#define NUM_TELLERS 128 -#define TRANSACTIONS_PER_TELLER 1000 - -// Monetary value in cents -typedef long currency; - -void sprintf_currency(char *buffer, currency c) { - if (c < 0) { - c = -c; - sprintf(buffer, "-"); - buffer += sizeof(char); - } - sprintf(buffer, "$%ld.%.2ld", c / 100, c % 100); -} - -void printf_currency(currency c) { - if (c < 0) { - c = -c; - printf("-"); - } - printf("$%ld.%.2ld", c / 100, c % 100); -} - -// Accounts (shared resource) -typedef struct account { - int account_id; - currency balance; - int transaction_count; - pthread_mutex_t lock; // Account access mutex -} account; - -void deposit(account *acc, currency amount) { - pthread_mutex_lock(&acc->lock); - // CRITICAL SECTION BEGIN - acc->balance += amount; - acc->transaction_count++; - // CRITICAL SECTION END - pthread_mutex_unlock(&acc->lock); -} - -// Global account array -account accounts[NUM_ACCOUNTS]; - -// Teller threads - -pthread_t tellers[NUM_TELLERS]; - -typedef struct teller_args { - int teller_id; - currency total; -} teller_args; - -void *teller_thread(void *arg) { - teller_args *args = (teller_args *)arg; - int id = args->teller_id; - currency total = 0; - - unsigned int seed = time(NULL) + pthread_self(); - for (int i = 0; i < TRANSACTIONS_PER_TELLER; i++) { - // Deposit or withdraw random currency amount from $0 to $1000 - currency random_amount = ((long)rand_r(&seed)) % 100000; - - char *operation; - currency random_amount_i = random_amount; - if (rand_r(&seed) % 2) { - random_amount_i = -random_amount; - operation = "Withdrawing"; - } else { - operation = "Depositing"; - } - - int random_acc = rand_r(&seed) % NUM_ACCOUNTS; - deposit(&accounts[random_acc], random_amount_i); - - // Display result of transaction - char buffer[8]; - sprintf_currency(buffer, random_amount); - printf("Thread %u: %s %s into account %u\n", id, operation, buffer, - random_acc); - - total += random_amount_i; - } - - args->total = total; - return NULL; -} - -int main() { - // Initialize all accounts with 0 balance - for (int i = 0; i < NUM_ACCOUNTS; i++) { - accounts[i] = (account){.account_id = i, .balance = 0}; - pthread_mutex_init(&accounts[i].lock, NULL); - } - - // Initialize tellers - teller_args args[NUM_TELLERS]; - for (int i = 0; i < NUM_TELLERS; i++) { - args[i] = (teller_args){.teller_id = i}; - pthread_create(&tellers[i], NULL, teller_thread, &args[i]); - } - - // Wait for all threads to finish - currency expected_total = 0; - for (int i = 0; i < NUM_TELLERS; i++) { - pthread_join(tellers[i], NULL); - expected_total += args[i].total; - } - - currency actual_total = 0; - for (int i = 0; i < NUM_ACCOUNTS; i++) { - actual_total += accounts[i].balance; - } - - printf("Total balance: "); - printf_currency(actual_total); - printf("\nExpected total: "); - printf_currency(expected_total); - printf("\n"); - - return 0; -} diff --git a/project1/phase3/output.png b/project1/phase3/output.png deleted file mode 100644 index 41e1515..0000000 Binary files a/project1/phase3/output.png and /dev/null differ diff --git a/project1/phase3/phase3.c b/project1/phase3/phase3.c deleted file mode 100644 index 27862a3..0000000 --- a/project1/phase3/phase3.c +++ /dev/null @@ -1,105 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -#define NUM_ACCOUNTS 5 -#define NUM_TRANSFERS 5 - -// Monetary value in cents -typedef long currency; - -void sprintf_currency(char *buffer, currency c) { - if (c < 0) { - c = -c; - sprintf(buffer, "-"); - buffer += sizeof(char); - } - sprintf(buffer, "$%ld.%.2ld", c / 100, c % 100); -} - -void printf_currency(currency c) { - if (c < 0) { - c = -c; - printf("-"); - } - printf("$%ld.%.2ld", c / 100, c % 100); -} - -// Accounts (shared resource) -typedef struct account { - int account_id; - currency balance; - int transaction_count; - pthread_mutex_t lock; // Account access mutex -} account; - -// Global account array -account accounts[NUM_ACCOUNTS]; - -// Threads - -pthread_t transfers[NUM_TRANSFERS]; - -typedef struct transfer_args { - int transfer_id; - account *from; - account *to; - currency amount; -} transfer_args; - -void *transfer_thread(void *arg) { - transfer_args *args = (transfer_args *)arg; - int id = args->transfer_id; - account *from = args->from; - account *to = args->to; - currency amount = args->amount; - - pthread_mutex_lock(&from->lock); - printf("Thread %u: Locked account %d\n", id, from->account_id); - - usleep(100); // Delay to account for other threads - - pthread_mutex_lock(&to->lock); - printf("Thread %u: Locked account %d\n", id, to->account_id); - - from->balance -= amount; - to->balance += amount; - from->transaction_count++; - to->transaction_count++; - - printf("Thread %u: Unlocked account %u\n", id, from->account_id); - printf("Thread %u: Unlocked account %u\n", id, to->account_id); - pthread_mutex_unlock(&to->lock); - pthread_mutex_unlock(&from->lock); - - return NULL; -} - -int main() { - // Initialize all accounts with 0 balance - for (int i = 0; i < NUM_ACCOUNTS; i++) { - accounts[i] = (account){.account_id = i, .balance = 0}; - pthread_mutex_init(&accounts[i].lock, NULL); - } - - // Initialize transfers - transfer_args args[NUM_TRANSFERS]; - for (int i = 0; i < NUM_TRANSFERS; i++) { - args[i] = (transfer_args){.transfer_id = i, - .from = &accounts[i % NUM_ACCOUNTS], - .to = &accounts[(i + 1) % NUM_ACCOUNTS], - .amount = 1000}; - pthread_create(&transfers[i], NULL, transfer_thread, &args[i]); - } - - // Wait for all threads to finish - for (int i = 0; i < NUM_TRANSFERS; i++) { - pthread_join(transfers[i], NULL); - } - - return 0; -} diff --git a/project1/phase4/mistake.png b/project1/phase4/mistake.png deleted file mode 100644 index 860c850..0000000 Binary files a/project1/phase4/mistake.png and /dev/null differ diff --git a/project1/phase4/output.png b/project1/phase4/output.png deleted file mode 100644 index 5e346b4..0000000 Binary files a/project1/phase4/output.png and /dev/null differ diff --git a/project1/phase4/output_wrong.png b/project1/phase4/output_wrong.png deleted file mode 100644 index 01574a4..0000000 Binary files a/project1/phase4/output_wrong.png and /dev/null differ diff --git a/project1/phase4/phase4.c b/project1/phase4/phase4.c deleted file mode 100644 index bc1c38d..0000000 --- a/project1/phase4/phase4.c +++ /dev/null @@ -1,124 +0,0 @@ -#include "bits/time.h" -#include -#include -#include -#include -#include -#include -#include - -#define NUM_ACCOUNTS 5 -#define NUM_TRANSFERS 20 - -// Monetary value in cents -typedef long currency; - -void sprintf_currency(char *buffer, currency c) { - if (c < 0) { - c = -c; - sprintf(buffer, "-"); - buffer += sizeof(char); - } - sprintf(buffer, "$%ld.%.2ld", c / 100, c % 100); -} - -void printf_currency(currency c) { - if (c < 0) { - c = -c; - printf("-"); - } - printf("$%ld.%.2ld", c / 100, c % 100); -} - -// Accounts (shared resource) -typedef struct account { - int account_id; - currency balance; - int transaction_count; - pthread_mutex_t lock; // Account access mutex -} account; - -// Global account array -account accounts[NUM_ACCOUNTS]; - -// Threads - -pthread_t transfers[NUM_TRANSFERS]; - -typedef struct transfer_args { - int transfer_id; - account *from; - account *to; - currency amount; -} transfer_args; - -void *transfer_thread(void *arg) { - transfer_args *args = (transfer_args *)arg; - int id = args->transfer_id; - account *from = args->from; - account *to = args->to; - currency amount = args->amount; - - // Sort in increasing order - account *acc1; - account *acc2; - if (from->account_id < to->account_id) { - acc1 = from; - acc2 = to; - } else { - acc1 = to; - acc2 = from; - } - - pthread_mutex_lock(&acc1->lock); - printf("Thread %u: Locked account %u (1)\n", id, acc1->account_id); - - usleep(100); // Delay to account for other threads - - pthread_mutex_lock(&acc2->lock); - printf("Thread %u: Locked account %u (2)\n", id, acc2->account_id); - - from->balance -= amount; - to->balance += amount; - from->transaction_count++; - to->transaction_count++; - - printf("Thread %u: Unlocked account %u\n", id, acc1->account_id); - printf("Thread %u: Unlocked account %u\n", id, acc2->account_id); - pthread_mutex_unlock(&acc2->lock); - pthread_mutex_unlock(&acc1->lock); - - return NULL; -} - -int main() { - // Initialize all accounts with 0 balance - for (int i = 0; i < NUM_ACCOUNTS; i++) { - accounts[i] = (account){.account_id = i, .balance = 0}; - pthread_mutex_init(&accounts[i].lock, NULL); - } - - // Initialize tellers - transfer_args args[NUM_TRANSFERS]; - for (int i = 0; i < NUM_TRANSFERS; i++) { - args[i] = (transfer_args){.transfer_id = i, - .from = &accounts[i % NUM_ACCOUNTS], - .to = &accounts[(i + 1) % NUM_ACCOUNTS], - .amount = 1000}; - pthread_create(&transfers[i], NULL, transfer_thread, &args[i]); - } - - // Wait for all threads to finish - for (int i = 0; i < NUM_TRANSFERS; i++) { - pthread_join(transfers[i], NULL); - } - - // Print account balance totals - for (int i = 0; i < NUM_ACCOUNTS; i++) { - printf("Total in account %u: ", i); - printf_currency(accounts[i].balance); - printf("\n"); - } - - return 0; -} diff --git a/project1/report/report.tex b/project1/report/report.tex deleted file mode 100644 index fc5a935..0000000 --- a/project1/report/report.tex +++ /dev/null @@ -1,177 +0,0 @@ -\documentclass{article} - -\usepackage{graphicx} -\usepackage{hyperref} - -\title{CS3502 Project 1: Resource Management and Deadlocks} -\author{Kiana Sheibani} - -\begin{document} -\maketitle -\newpage - -\section{Introduction} - -To demonstrate the basic principles of multi-threaded code, race conditions, and deadlock -avoidance, I ultimately decided to go with the model of a banking system, as that serves -as a simple and immediately applicable demonstration of the concept. - -The code for this project is stored in the \texttt{project1} subdirectory of my repository -for this class: \url{https://github.com/tokinanpa/CS3502}. - -\section{Phase 1: Basic Thread Operations} - -\subsection{Implementation} - -To start with, I simply needed some basic code of multiple threads trying to access and -manipulate an array of bank accounts. This code mostly looked similar to the example code -given in the instructions, except for the following differences: - -\begin{enumerate} - \item The currency amounts are stored as an integer number of cents instead of - floating point values, because that's the sensible thing to do. - \item Each thread is passed an argument struct that contains its own ID and a slot - for it to pass back the total amount it deposited or withdrew. -\end{enumerate} - -The program initializes an array of accounts (8) and of teller threads (128), then each -thread starts depositing or withdrawing a random amount of money up to \$1000 a certain -amount of times (100), while keeping a count of the total monetary influx that thread -introduced. After all threads have joined back up with the main program, the combined sum -from each thread (the \emph{expected total}) is compared with the sum of all account -balances (the \emph{actual total}). If no race conditions have occurred, these values -should be equal. - -\subsection{Results} - -\begin{figure}[h!] - \centering - \includegraphics[width=0.5\linewidth]{../phase1/output.png} - \caption{The output log of the Phase 1 program.} - \label{fig:result1} -\end{figure} - -As expected, the program did indeed demonstrate that race conditions had occurred between -the threads, as can be seen in \figurename~\ref{fig:result1}. You may notice that the -transaction logs are somewhat garbled; this is because the logs are generated through -multiple \texttt{printf} calls, resulting in another example of a race condition. I did -not yet fix this bug because the repeated I/O calls helped delay the threads' execution -and make race conditions more likely. - -\section{Phase 2: Resource Protection} - -\subsection{Implementation} - -This was a very small addition to the code for Phase 1, and just required adding a mutex -field \texttt{lock} to the account struct and initializing it at the beginning of the main -program. Each thread had to lock the mutex before the transaction and unlock it after, -which could be easily encapsulated into a subroutine \texttt{deposit} that takes a pointer -to the account and an amount. - -I also fixed the bug shown earlier that garbled the log output by combining the log into -one \texttt{printf} call, which required a bit of rearranging in my code for printing currency -values but was only a minor complication. - -\subsection{Results} - -\begin{figure}[h!] - \centering - \includegraphics[width=0.5\linewidth]{../phase2/output.png} - \caption{The output of Phase 2, showing total consistency.} - \label{fig:result2} -\end{figure} - -Even after increasing the number of transactions per teller from 100 to 1,000, the totals -always match up exactly. - -Notably, there seems to be large blocks of transactions coming from singular threads. This -happened in the first program as well, most likely as an artifact of scheduling, but the -blocks are much larger here. This may be due to threads repeatedly unlocking and -re-locking a mutex, thus allowing them to instantly make another transaction. - -\section{Phase 3: Deadlock Creation} - -\subsection{Implementation} - -It turns out that it's quite easy to make a program deadlock! I could have just had two -transactions competing for resources as in the example code, but I decided to implement a -more complex example. I kept the large array of threads, but changed the threads from -adding/subtracting random amounts to transferring money between two accounts. The accounts -to transfer between were passed as pointers to the threads using the struct-passing method -I outlined earlier, along with the amount to transfer (I arbitrarily picked \$10 for all threads). - -I then initialized the same number of threads as accounts, and set each of them to start a -transfer from one account to the next. Thread 0 transfers from 0 to 1, thread 1 transfers -from 1 to 2, etc. This would in theory create a large circle of threads that would -deadlock and prevent any transaction from completing. - -\subsection{Results} - -\begin{figure}[h!] - \centering - \includegraphics[width=0.5\linewidth]{../phase3/output.png} - \caption{The output of Phase 3 successfully generating a deadlock.} - \label{fig:result3} -\end{figure} - -The program hangs immediately once all threads have started, regardless of the number of -accounts or transfers I generate. - -\section{Phase 4: Deadlock Resolution} - -\subsection{Implementation} - -To resolve the issue of these deadlocks in this code, I ultimately decided to go with a -lock ordering approach. This is the simplest and easiest to implement of the possible -solutions, though no program involving asynchonous execution is truly simple. The idea is -to always lock the resources in a consistent, absolute order (in this case, the order of -the account IDs). This would prevent the threads from creating a cycle of lock -acquisitions, and thereby prevent any deadlocks from occurring. - -\subsubsection{Challenges} - -\begin{figure}[h!] - \centering - \includegraphics[width=0.5\linewidth]{../phase4/output_wrong.png} - \caption{This log output shows account 0 being locked multiple times!} - \label{fig:outputwrong} -\end{figure} - -After running the code with different parameters, in particular in the case of there being -more transfers than accounts, I ran into a strange bug. It seemed like the mutexes were -being locked multiple times at once, which should be impossible. The final balances of -each account seemed to confirm that race conditions were occurring, as the total did not -sum to 0, as should be the case when no transfer is adding or removing money from the -bank. - -\begin{figure}[h!] - \centering - \includegraphics[width=0.5\linewidth]{../phase4/mistake.png} - \caption{The offending line of code (line 105).} - \label{fig:mistake} -\end{figure} - -It took me a long time to discover the true problem: transactions were receiving invalid -account IDs because one specific line of code accidentally left off a modulo operator -(\texttt{i \% NUM\_ACCOUNTS}) to constrain the accounts referenced to inside the array. -This meant that ``accounts'' were modified that did not actually exist, thus violating the -preservation of the total sum of balances. The log output issue was completely unrelated -and seems to solely be an artifact of race conditions in I/O operations. After fixing the -aforementioned line of code, the final account balances were fully consistent. - -\subsection{Results} - -\begin{figure}[h!] - \centering - \includegraphics[width=0.5\linewidth]{../phase4/output.png} - \caption{The output log of Phase 4 showing consistent account balances.} - \label{fig:result4} -\end{figure} - -\figurename~\ref{fig:result4} shows that deadlocks have been completely avoided and that -no race conditions have occurred. This output was generated with 5 accounts and 20 -transfers, meaning that every account has multiple threads attempting to modify its -balance without issue. The performance is also unchanged from previous phases, which may -not be the case for the other deadlock resolution methods (e.g. timed locks). - -\end{document} diff --git a/project1/test.nix b/project1/test.nix deleted file mode 100644 index 0967ef4..0000000 --- a/project1/test.nix +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/shell.nix b/shell.nix index 1e140c8..cc840a0 100644 --- a/shell.nix +++ b/shell.nix @@ -1,10 +1,4 @@ -{ mkShell, llvmPackages_21 }: +{ mkShell }: -mkShell { - packages = [ - # GCC is provided by default - - # Provides clangd - llvmPackages_21.clang-tools - ]; -} +# GCC is provided by default +mkShell {}