From 4707552388de3b274348dda4a2237c343b3f418a Mon Sep 17 00:00:00 2001 From: un-lock-able Date: Tue, 22 Apr 2025 02:05:21 +0800 Subject: [PATCH] lab1 code --- .clang-format | 208 +++++++++++++++++++++++++++++++++++++++ .vscode/settings.json | 60 +++++++++++ lab1/.gitignore | 1 + lab1/Makefile | 2 +- lab1/banker.cpp | 183 ++++++++++++++++++++++++++++------ lab1/test_data/1_out.txt | 71 +++++++++++++ lab1/test_data/2.txt | 7 ++ lab1/test_data/2_out.txt | 130 ++++++++++++++++++++++++ 8 files changed, 629 insertions(+), 33 deletions(-) create mode 100644 .clang-format create mode 100644 .vscode/settings.json create mode 100644 lab1/.gitignore create mode 100644 lab1/test_data/1_out.txt create mode 100644 lab1/test_data/2.txt create mode 100644 lab1/test_data/2_out.txt diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..ca96c78 --- /dev/null +++ b/.clang-format @@ -0,0 +1,208 @@ +--- +Language: Cpp +# BasedOnStyle: LLVM +AccessModifierOffset: -4 +AlignAfterOpenBracket: Align +AlignArrayOfStructures: None +AlignConsecutiveAssignments: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + PadOperators: true +AlignConsecutiveBitFields: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + PadOperators: false +AlignConsecutiveDeclarations: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + PadOperators: false +AlignConsecutiveMacros: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + PadOperators: false +AlignEscapedNewlines: Right +AlignOperands: Align +AlignTrailingComments: true +AllowAllArgumentsOnNextLine: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortEnumsOnASingleLine: true +AllowShortBlocksOnASingleLine: Never +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: false +AllowShortLambdasOnASingleLine: All +AllowShortIfStatementsOnASingleLine: Never +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: MultiLine +AttributeMacros: + - __capability +BinPackArguments: true +BinPackParameters: true +BraceWrapping: + AfterCaseLabel: false + AfterClass: false + AfterControlStatement: Never + AfterEnum: false + AfterFunction: false + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + AfterExternBlock: false + BeforeCatch: true + BeforeElse: false + BeforeLambdaBody: false + BeforeWhile: false + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true +BreakBeforeBinaryOperators: None +BreakBeforeConceptDeclarations: Always +BreakBeforeBraces: Custom +BreakBeforeInheritanceComma: false +BreakInheritanceList: BeforeColon +BreakBeforeTernaryOperators: true +BreakConstructorInitializersBeforeComma: false +BreakConstructorInitializers: BeforeColon +BreakAfterJavaFieldAnnotations: false +BreakStringLiterals: true +ColumnLimit: 80 +CommentPragmas: '^ IWYU pragma:' +QualifierAlignment: Leave +CompactNamespaces: false +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DeriveLineEnding: true +DerivePointerAlignment: false +DisableFormat: false +EmptyLineAfterAccessModifier: Never +EmptyLineBeforeAccessModifier: LogicalBlock +ExperimentalAutoDetectBinPacking: false +PackConstructorInitializers: BinPack +BasedOnStyle: '' +ConstructorInitializerAllOnOneLineOrOnePerLine: false +AllowAllConstructorInitializersOnNextLine: true +FixNamespaceComments: true +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH +IfMacros: + - KJ_IF_MAYBE +IncludeBlocks: Preserve +IncludeCategories: + - Regex: '^"(llvm|llvm-c|clang|clang-c)/' + Priority: 2 + SortPriority: 0 + CaseSensitive: false + - Regex: '^(<|"(gtest|gmock|isl|json)/)' + Priority: 3 + SortPriority: 0 + CaseSensitive: false + - Regex: '.*' + Priority: 1 + SortPriority: 0 + CaseSensitive: false +IncludeIsMainRegex: '(Test)?$' +IncludeIsMainSourceRegex: '' +IndentAccessModifiers: false +IndentCaseLabels: false +IndentCaseBlocks: false +IndentGotoLabels: true +IndentPPDirectives: None +IndentExternBlock: AfterExternBlock +IndentRequiresClause: true +IndentWidth: 4 +IndentWrappedFunctionNames: false +InsertBraces: false +InsertTrailingCommas: None +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLinesAtTheStartOfBlocks: true +LambdaBodyIndentation: Signature +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCBinPackProtocolList: Auto +ObjCBlockIndentWidth: 2 +ObjCBreakBeforeNestedBlockParam: true +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PenaltyBreakAssignment: 2 +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakOpenParenthesis: 0 +PenaltyBreakString: 1000 +PenaltyBreakTemplateDeclaration: 10 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 60 +PenaltyIndentedWhitespace: 0 +PointerAlignment: Right +PPIndentWidth: -1 +ReferenceAlignment: Pointer +ReflowComments: true +RemoveBracesLLVM: false +RequiresClausePosition: OwnLine +SeparateDefinitionBlocks: Leave +ShortNamespaceLines: 1 +SortIncludes: CaseSensitive +SortJavaStaticImport: Before +SortUsingDeclarations: true +SpaceAfterCStyleCast: false +SpaceAfterLogicalNot: false +SpaceAfterTemplateKeyword: true +SpaceBeforeAssignmentOperators: true +SpaceBeforeCaseColon: false +SpaceBeforeCpp11BracedList: false +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeParens: ControlStatements +SpaceBeforeParensOptions: + AfterControlStatements: true + AfterForeachMacros: true + AfterFunctionDefinitionName: false + AfterFunctionDeclarationName: false + AfterIfMacros: true + AfterOverloadedOperator: false + AfterRequiresInClause: false + AfterRequiresInExpression: false + BeforeNonEmptyParentheses: false +SpaceAroundPointerQualifiers: Default +SpaceBeforeRangeBasedForLoopColon: true +SpaceInEmptyBlock: false +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: Never +SpacesInConditionalStatement: false +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInLineCommentPrefix: + Minimum: 1 + Maximum: -1 +SpacesInParentheses: false +SpacesInSquareBrackets: false +SpaceBeforeSquareBrackets: false +BitFieldColonSpacing: Both +Standard: Latest +StatementAttributeLikeMacros: + - Q_EMIT +StatementMacros: + - Q_UNUSED + - QT_REQUIRE_VERSION +TabWidth: 4 +UseCRLF: false +UseTab: Never diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..42656c5 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,60 @@ +{ + "files.associations": { + "array": "cpp", + "atomic": "cpp", + "bit": "cpp", + "*.tcc": "cpp", + "cctype": "cpp", + "chrono": "cpp", + "clocale": "cpp", + "cmath": "cpp", + "compare": "cpp", + "concepts": "cpp", + "condition_variable": "cpp", + "cstdarg": "cpp", + "cstddef": "cpp", + "cstdint": "cpp", + "cstdio": "cpp", + "cstdlib": "cpp", + "ctime": "cpp", + "cwchar": "cpp", + "cwctype": "cpp", + "deque": "cpp", + "string": "cpp", + "unordered_map": "cpp", + "vector": "cpp", + "exception": "cpp", + "algorithm": "cpp", + "functional": "cpp", + "iterator": "cpp", + "memory": "cpp", + "memory_resource": "cpp", + "numeric": "cpp", + "random": "cpp", + "ratio": "cpp", + "string_view": "cpp", + "system_error": "cpp", + "tuple": "cpp", + "type_traits": "cpp", + "utility": "cpp", + "initializer_list": "cpp", + "iosfwd": "cpp", + "iostream": "cpp", + "istream": "cpp", + "limits": "cpp", + "mutex": "cpp", + "new": "cpp", + "numbers": "cpp", + "ostream": "cpp", + "semaphore": "cpp", + "stdexcept": "cpp", + "stop_token": "cpp", + "streambuf": "cpp", + "thread": "cpp", + "typeinfo": "cpp", + "syncstream": "cpp", + "csignal": "cpp", + "sstream": "cpp", + "fstream": "cpp" + } +} \ No newline at end of file diff --git a/lab1/.gitignore b/lab1/.gitignore new file mode 100644 index 0000000..d163863 --- /dev/null +++ b/lab1/.gitignore @@ -0,0 +1 @@ +build/ \ No newline at end of file diff --git a/lab1/Makefile b/lab1/Makefile index 81f364a..fb9fd9d 100644 --- a/lab1/Makefile +++ b/lab1/Makefile @@ -3,7 +3,7 @@ OUT_BIN := $(OUT_DIR)/banker $(OUT_BIN): banker.cpp mkdir -p $(OUT_DIR) - g++ -pthread banker.cpp -o $(OUT_BIN) + g++ -pthread --std=c++20 banker.cpp -o $(OUT_BIN) .PHONY: run run: $(OUT_BIN) diff --git a/lab1/banker.cpp b/lab1/banker.cpp index 68fc75d..da7d819 100644 --- a/lab1/banker.cpp +++ b/lab1/banker.cpp @@ -1,22 +1,19 @@ -#include -#include -#include -#include -#include #include +#include +#include +#include +#include +#include #include #include +#include +#include +#include +#include -#define TELLER_NUM 5 +#define TELLER_NUM 3 #define TIME_GRAN_MSEC 200 -std::atomic bank_open = false; -std::mutex custom_q_mtx; -std::counting_semaphore custom_num_sem; - -std::deque customer_q; - - struct CustomerInfo { unsigned int id; unsigned int arrival_time; @@ -28,42 +25,164 @@ struct Customer { unsigned int service_time; }; -void teller_thread(int id, std::chrono::time_point start_tick) { - std::cout << "Teller id " << id << " started\n"; +std::atomic bank_open{false}; +std::mutex customer_q_mtx; +std::counting_semaphore<100> customer_num_sem{0}; + +std::deque customer_q; + +void signal_handler(int signum) { + // std::cout << "\nReceived signal " << signum << ", stopping...\n"; + write(STDOUT_FILENO, "\nCaught SIGINT, shutting down...\n", 33); + bank_open = false; +} + +void teller_thread( + int id, std::chrono::time_point start_tick) { + std::osyncstream(std::cout) + << "Teller id " << id << " started" << std::endl; std::chrono::time_point curr_tick = start_tick; + unsigned int tick_count = 0; bool is_serving = false; std::chrono::time_point start_serving_time; struct Customer curr_customer; while (bank_open) { - if (is_serving && ((curr_tick - start_serving_time) / TIME_GRAN_MSEC) >= curr_customer.service_time) { - + if (is_serving) { + if ((std::chrono::duration_cast( + (curr_tick - start_serving_time) / TIME_GRAN_MSEC)) + .count() <= curr_customer.service_time) { + // We are still serving, do nothing + std::osyncstream(std::cout) << "Teller id " << id << " is serving customer " << curr_customer.id << " at tick " << tick_count << std::endl; + goto next_tick; + } else { + // We have just finished serving. + std::osyncstream(std::cout) << "Teller id " << id << " finishied serving customer " << curr_customer.id << " at tick " << tick_count << std::endl; + is_serving = false; + } } - std::cout << "Teller id " << id << " waiting request\n"; - + // Try to acquire a new customer + if (customer_num_sem.try_acquire()) { + // Successfully acquired a customer + std::lock_guard lock(customer_q_mtx); + if (!customer_q.empty()) { + curr_customer = customer_q.front(); + customer_q.pop_front(); + + std::osyncstream(std::cout) + << "Teller id " << id << " is now serving customer " + << curr_customer.id << " for " << curr_customer.service_time + << " ticks at tick " << tick_count << std::endl; + + is_serving = true; + start_serving_time = curr_tick; + } + } else { + std::osyncstream(std::cout) + << "Teller id " << id << " is idle at tick " << tick_count << std::endl; + } + + next_tick: + ++tick_count; curr_tick += std::chrono::milliseconds(TIME_GRAN_MSEC); std::this_thread::sleep_until(curr_tick); } - std::cout << "Teller id " << id << " closing\n"; + std::osyncstream(std::cout) + << "Teller id " << id << " closing" << std::endl; } -int main() { - bank_open = true; +void customer_thread( + CustomerInfo info, + std::chrono::time_point start_tick) { - std::vector tellers; - for (int i = 0; i < TELLER_NUM; ++i) { - try { - tellers.emplace_back(teller_thread, i); - } catch (const std::system_error& e) { - std::cerr << "Failed to create thread, i = " << i << ": " << e.what() << '\n'; + Customer cus{.id = info.id, .service_time = info.service_time}; + + std::chrono::time_point curr_tick = start_tick; + unsigned int tick_count = 0; + std::chrono::time_point target_tick = start_tick + std::chrono::milliseconds(TIME_GRAN_MSEC) * info.arrival_time; + while (curr_tick < target_tick) { + if (!bank_open) { + return; + } + ++tick_count; + curr_tick += std::chrono::milliseconds(TIME_GRAN_MSEC); + std::this_thread::sleep_until(curr_tick); + } + + // Wake up and push self into queue, then V(customer_num_sem) + std::osyncstream(std::cout) << "Customer id " << info.id << " arrived at tick " << tick_count << std::endl; + { + std::lock_guard lock(customer_q_mtx); + customer_q.push_back(cus); + } + customer_num_sem.release(); +} + +int main(int argc, char *argv[]) { + if (argc != 2) { + std::cout << "Invalid commandline arg, expected filename"; + return 1; + } + + std::signal(SIGINT, signal_handler); + + // Read config from file + std::vector customer_infos; + + std::ifstream file(argv[1]); + if (!file.is_open()) { + std::cerr << "Cannot open file: " << argv[1] << std::endl; + return 1; + } + + std::string line; + while (std::getline(file, line)) { + std::istringstream iss(line); + CustomerInfo cus; + if (iss >> cus.id >> cus.arrival_time >> cus.service_time) { + customer_infos.push_back(cus); + } else { + std::cerr << "Invalid line: " << line << std::endl; } } - std::this_thread::sleep_for(std::chrono::milliseconds(5 * TIME_GRAN_MSEC)); - std::cout << "Closing all child\n"; - bank_open = false; + file.close(); - for (auto& t : tellers) { + bank_open = true; + std::chrono::time_point start_tick = std::chrono::steady_clock::now(); + + // Set up tellers + std::vector tellers; + + for (int i = 0; i < TELLER_NUM; ++i) { + try { + tellers.emplace_back(teller_thread, i, start_tick); + } + catch (const std::system_error &e) { + std::cerr << "Failed to create teller thread, i = " << i << ": " + << e.what() << std::endl; + } + } + + // Set up customers + std::vector customers; + for (auto cu : customer_infos) { + try { + customers.emplace_back(customer_thread, cu, start_tick); + } catch (const std::system_error &e) { + std::cerr << "Failed to create customer thread, id = " << cu.id << ": " + << e.what() << std::endl; + } + } + + // Wait for all children to shutdown (by ctrl-c handler) + for (auto &t: customers) { + if (t.joinable()) { + t.join(); + } + } + + for (auto &t : tellers) { if (t.joinable()) { t.join(); } diff --git a/lab1/test_data/1_out.txt b/lab1/test_data/1_out.txt new file mode 100644 index 0000000..f1b830f --- /dev/null +++ b/lab1/test_data/1_out.txt @@ -0,0 +1,71 @@ +Teller id 0 started +Teller id 1 started +Teller id 1 is idle at tick 0 +Teller id 0 is idle at tick 0 +Teller id 2 started +Teller id 2 is idle at tick 0 +Teller id 0 is idle at tick 1 +Teller id 2 is idle at tick 1 +Teller id 1 is idle at tick 1 +Customer id 1 arrived at tick 1 +Teller id 0 is now serving customer 1 for 10 ticks at tick 2 +Teller id 1 is idle at tick 2 +Teller id 2 is idle at tick 2 +Teller id 0 is serving customer 1 at tick 3 +Teller id 1 is idle at tick 3 +Teller id 2 is idle at tick 3 +Teller id 0 is serving customer 1 at tick 4 +Teller id 1 is idle at tick 4 +Teller id 2 is idle at tick 4 +Teller id 0 is serving customer 1 at tick 5 +Customer id 2 arrived at tick 5 +Teller id 2 is idle at tick 5 +Teller id 1 is idle at tick 5 +Teller id 0 is serving customer 1 at tick 6 +Teller id 2 is now serving customer 2 for 2 ticks at tick 6 +Customer id 3 arrived at tick 6 +Teller id 1 is idle at tick 6 +Teller id 0 is serving customer 1 at tick 7 +Teller id 1 is now serving customer 3 for 3 ticks at tick 7 +Teller id 2 is serving customer 2 at tick 7 +Teller id 0 is serving customer 1 at tick 8 +Teller id 1 is serving customer 3 at tick 8 +Teller id 2 is serving customer 2 at tick 8 +Teller id 0 is serving customer 1 at tick 9 +Teller id 1 is serving customer 3 at tick 9 +Teller id 2 finishied serving customer 2 at tick 9 +Teller id 2 is idle at tick 9 +Teller id 1 is serving customer 3 at tick 10 +Teller id 0 is serving customer 1 at tick 10 +Teller id 2 is idle at tick 10 +Teller id 0 is serving customer 1 at tick 11 +Teller id 1 finishied serving customer 3 at tick 11 +Teller id 2 is idle at tick 11 +Teller id 1 is idle at tick 11 +Teller id 1 is idle at tick 12 +Teller id 2 is idle at tick 12 +Teller id 0 is serving customer 1 at tick 12 +Teller id 0 finishied serving customer 1 at tick 13 +Teller id 0 is idle at tick 13 +Teller id 2 is idle at tick 13 +Teller id 1 is idle at tick 13 +Teller id 0 is idle at tick 14 +Teller id 1 is idle at tick 14 +Teller id 2 is idle at tick 14 +Teller id 0 is idle at tick 15 +Teller id 2 is idle at tick 15 +Teller id 1 is idle at tick 15 +Teller id 0 is idle at tick 16 +Teller id 1 is idle at tick 16 +Teller id 2 is idle at tick 16 +Teller id 2 is idle at tick 17 +Teller id 0 is idle at tick 17 +Teller id 1 is idle at tick 17 +Teller id 0 is idle at tick 18 +Teller id 1 is idle at tick 18 +Teller id 2 is idle at tick 18 +^C +Caught SIGINT, shutting down... +Teller id 0 closing +Teller id 1 closing +Teller id 2 closing \ No newline at end of file diff --git a/lab1/test_data/2.txt b/lab1/test_data/2.txt new file mode 100644 index 0000000..4313875 --- /dev/null +++ b/lab1/test_data/2.txt @@ -0,0 +1,7 @@ +1 1 10 +2 2 10 +3 3 10 +4 4 10 +5 5 5 +6 6 7 +8 7 10 \ No newline at end of file diff --git a/lab1/test_data/2_out.txt b/lab1/test_data/2_out.txt new file mode 100644 index 0000000..3aca3fe --- /dev/null +++ b/lab1/test_data/2_out.txt @@ -0,0 +1,130 @@ +Teller id 1 started +Teller id 0 started +Teller id 2 started +Teller id 1 is idle at tick 0 +Teller id 2 is idle at tick 0 +Teller id 0 is idle at tick 0 +Teller id 0 is idle at tick 1 +Teller id 2 is idle at tick 1 +Teller id 1 is idle at tick 1 +Customer id 1 arrived at tick 1 +Teller id 0 is now serving customer 1 for 10 ticks at tick 2 +Teller id 1 is idle at tick 2 +Teller id 2 is idle at tick 2 +Customer id 2 arrived at tick 2 +Teller id 1 is now serving customer 2 for 10 ticks at tick 3 +Customer id 3 arrived at tick 3 +Teller id 0 is serving customer 1 at tick 3 +Teller id 2 is idle at tick 3 +Teller id 0 is serving customer 1 at tick 4 +Teller id 2 is now serving customer 3 for 10 ticks at tick 4 +Teller id 1 is serving customer 2 at tick 4 +Customer id 4 arrived at tick 4 +Teller id 0 is serving customer 1 at tick 5 +Teller id 2 is serving customer 3 at tick 5 +Teller id 1 is serving customer 2 at tick 5 +Customer id 5 arrived at tick 5 +Customer id 6 arrived at tick 6 +Teller id 1 is serving customer 2 at tick 6 +Teller id 0 is serving customer 1 at tick 6 +Teller id 2 is serving customer 3 at tick 6 +Teller id 1 is serving customer 2 at tick 7 +Teller id 0 is serving customer 1 at tick 7 +Customer id 8 arrived at tick 7 +Teller id 2 is serving customer 3 at tick 7 +Teller id 1 is serving customer 2 at tick 8 +Teller id 2 is serving customer 3 at tick 8 +Teller id 0 is serving customer 1 at tick 8 +Teller id 2 is serving customer 3 at tick 9 +Teller id 1 is serving customer 2 at tick 9 +Teller id 0 is serving customer 1 at tick 9 +Teller id 0 is serving customer 1 at tick 10 +Teller id 2 is serving customer 3 at tick 10 +Teller id 1 is serving customer 2 at tick 10 +Teller id 2 is serving customer 3 at tick 11 +Teller id 1 is serving customer 2 at tick 11 +Teller id 0 is serving customer 1 at tick 11 +Teller id 1 is serving customer 2 at tick 12 +Teller id 2 is serving customer 3 at tick 12 +Teller id 0 is serving customer 1 at tick 12 +Teller id 2 is serving customer 3 at tick 13 +Teller id 1 is serving customer 2 at tick 13 +Teller id 0 finishied serving customer 1 at tick 13 +Teller id 0 is now serving customer 4 for 10 ticks at tick 13 +Teller id 2 is serving customer 3 at tick 14 +Teller id 1 finishied serving customer 2 at tick 14 +Teller id 1 is now serving customer 5 for 5 ticks at tick 14 +Teller id 0 is serving customer 4 at tick 14 +Teller id 2 finishied serving customer 3 at tick 15 +Teller id 2 is now serving customer 6 for 7 ticks at tick 15 +Teller id 1 is serving customer 5 at tick 15 +Teller id 0 is serving customer 4 at tick 15 +Teller id 2 is serving customer 6 at tick 16 +Teller id 1 is serving customer 5 at tick 16 +Teller id 0 is serving customer 4 at tick 16 +Teller id 2 is serving customer 6 at tick 17 +Teller id 0 is serving customer 4 at tick 17 +Teller id 1 is serving customer 5 at tick 17 +Teller id 2 is serving customer 6 at tick 18 +Teller id 1 is serving customer 5 at tick 18 +Teller id 0 is serving customer 4 at tick 18 +Teller id 2 is serving customer 6 at tick 19 +Teller id 0 is serving customer 4 at tick 19 +Teller id 1 is serving customer 5 at tick 19 +Teller id 0 is serving customer 4 at tick 20 +Teller id 1 finishied serving customer 5 at tick 20 +Teller id 1 is now serving customer 8 for 10 ticks at tick 20 +Teller id 2 is serving customer 6 at tick 20 +Teller id 1 is serving customer 8 at tick 21 +Teller id 0 is serving customer 4 at tick 21 +Teller id 2 is serving customer 6 at tick 21 +Teller id 2 is serving customer 6 at tick 22 +Teller id 1 is serving customer 8 at tick 22 +Teller id 0 is serving customer 4 at tick 22 +Teller id 1 is serving customer 8 at tick 23 +Teller id 2 finishied serving customer 6 at tick 23 +Teller id 2 is idle at tick 23 +Teller id 0 is serving customer 4 at tick 23 +Teller id 1 is serving customer 8 at tick 24 +Teller id 0 finishied serving customer 4 at tick 24 +Teller id 2 is idle at tick 24 +Teller id 0 is idle at tick 24 +Teller id 1 is serving customer 8 at tick 25 +Teller id 2 is idle at tick 25 +Teller id 0 is idle at tick 25 +Teller id 1 is serving customer 8 at tick 26 +Teller id 2 is idle at tick 26 +Teller id 0 is idle at tick 26 +Teller id 1 is serving customer 8 at tick 27 +Teller id 0 is idle at tick 27 +Teller id 2 is idle at tick 27 +Teller id 1 is serving customer 8 at tick 28 +Teller id 2 is idle at tick 28 +Teller id 0 is idle at tick 28 +Teller id 1 is serving customer 8 at tick 29 +Teller id 2 is idle at tick 29 +Teller id 0 is idle at tick 29 +Teller id 1 is serving customer 8 at tick 30 +Teller id 0 is idle at tick 30 +Teller id 2 is idle at tick 30 +Teller id 1 finishied serving customer 8 at tick 31 +Teller id 1 is idle at tick 31 +Teller id 0 is idle at tick 31 +Teller id 2 is idle at tick 31 +Teller id 1 is idle at tick 32 +Teller id 2 is idle at tick 32 +Teller id 0 is idle at tick 32 +Teller id 1 is idle at tick 33 +Teller id 2 is idle at tick 33 +Teller id 0 is idle at tick 33 +Teller id 0 is idle at tick 34 +Teller id 1 is idle at tick 34 +Teller id 2 is idle at tick 34 +Teller id 0 is idle at tick 35 +Teller id 1 is idle at tick 35 +Teller id 2 is idle at tick 35 +^C +Caught SIGINT, shutting down... +Teller id 1 closing +Teller id 0 closing +Teller id 2 closing \ No newline at end of file