From 31c32e368adc011e5eac93a55d4e1e387a3d6a3e Mon Sep 17 00:00:00 2001 From: Bassem Girgis Date: Thu, 18 Oct 2018 00:40:34 -0500 Subject: [PATCH] Run clang-format --- .clang-format | 104 +++++++++ .cproject | 114 ++++++++++ .project | 27 +++ .settings/language.settings.xml | 25 ++ ch1/hello.cpp | 17 +- ch2/accumulate.cpp | 90 ++++---- ch3/hierarchical.cpp | 93 ++++---- ch3/stack.cpp | 110 +++++---- ch4/queue.cpp | 171 +++++++------- ch4/quicksort.cpp | 116 +++++----- ch6/list.cpp | 201 ++++++++-------- ch6/lookuptable.cpp | 205 ++++++++--------- ch6/queue.cpp | 183 +++++++-------- ch6/queuelist.cpp | 147 ++++++------ ch6/queuelist2.cpp | 261 +++++++++++---------- ch6/stack.cpp | 91 ++++---- ch7/hazard_pointer.h | 92 ++++---- ch7/queue_mpmc.cpp | 392 +++++++++++++++----------------- ch7/queue_spsc.cpp | 158 +++++++------ ch7/stack.cpp | 267 +++++++++++----------- ch7/stack_hp.cpp | 306 +++++++++++++------------ ch7/stack_ref.cpp | 310 ++++++++++++------------- ch7/stack_sp.cpp | 112 ++++----- source/listing_1.1.cpp | 12 +- source/listing_10.1.cpp | 65 +++--- source/listing_2.1.cpp | 40 ++-- source/listing_2.2.cpp | 61 ++--- source/listing_2.3.cpp | 77 ++++--- source/listing_2.4.cpp | 84 +++---- source/listing_2.5.cpp | 47 ++-- source/listing_2.6.cpp | 73 +++--- source/listing_2.7.cpp | 33 +-- source/listing_2.8.cpp | 95 ++++---- source/listing_3.1.cpp | 26 ++- source/listing_3.10.cpp | 42 ++-- source/listing_3.11.cpp | 29 ++- source/listing_3.12.cpp | 83 ++++--- source/listing_3.13.cpp | 54 ++--- source/listing_3.2.cpp | 48 ++-- source/listing_3.3.cpp | 43 ++-- source/listing_3.4.cpp | 30 +-- source/listing_3.5.cpp | 110 +++++---- source/listing_3.6.cpp | 54 +++-- source/listing_3.7.cpp | 78 ++++--- source/listing_3.8.cpp | 91 ++++---- source/listing_3.9.cpp | 54 +++-- source/listing_4.1.cpp | 84 +++---- source/listing_4.10.cpp | 41 ++-- source/listing_4.11.cpp | 22 +- source/listing_4.12.cpp | 41 ++-- source/listing_4.13.cpp | 40 ++-- source/listing_4.14.cpp | 17 +- source/listing_4.15.cpp | 70 +++--- source/listing_4.16.cpp | 47 ++-- source/listing_4.2.cpp | 48 ++-- source/listing_4.3.cpp | 31 +-- source/listing_4.4.cpp | 77 ++++--- source/listing_4.5.cpp | 121 +++++----- source/listing_4.6.cpp | 22 +- source/listing_4.7.cpp | 42 ++-- source/listing_4.8.cpp | 13 +- source/listing_4.9.cpp | 43 ++-- source/listing_5.1.cpp | 24 +- source/listing_5.10.cpp | 51 +++-- source/listing_5.11.cpp | 52 ++--- source/listing_5.12.cpp | 44 ++-- source/listing_5.13.cpp | 44 ++-- source/listing_5.2.cpp | 23 +- source/listing_5.3.cpp | 17 +- source/listing_5.4.cpp | 61 ++--- source/listing_5.5.cpp | 40 ++-- source/listing_5.6.cpp | 102 ++++----- source/listing_5.7.cpp | 61 ++--- source/listing_5.8.cpp | 40 ++-- source/listing_5.9.cpp | 58 ++--- source/listing_6.1.cpp | 90 ++++---- source/listing_6.10.cpp | 67 +++--- source/listing_6.11.cpp | 171 +++++++------- source/listing_6.12.cpp | 31 ++- source/listing_6.13.cpp | 160 ++++++------- source/listing_6.2.cpp | 112 +++++---- source/listing_6.3.cpp | 109 +++++---- source/listing_6.4.cpp | 81 +++---- source/listing_6.5.cpp | 71 +++--- source/listing_6.6.cpp | 98 ++++---- source/listing_6.7.cpp | 49 ++-- source/listing_6.8.cpp | 26 +-- source/listing_6.9.cpp | 81 ++++--- source/listing_7.1.cpp | 24 +- source/listing_7.10.cpp | 61 +++-- source/listing_7.11.cpp | 74 +++--- source/listing_7.12.cpp | 146 ++++++------ source/listing_7.13.cpp | 100 ++++---- source/listing_7.14.cpp | 32 ++- source/listing_7.15.cpp | 101 ++++---- source/listing_7.16.cpp | 50 ++-- source/listing_7.17.cpp | 42 ++-- source/listing_7.18.cpp | 33 ++- source/listing_7.19.cpp | 43 ++-- source/listing_7.2.cpp | 34 ++- source/listing_7.20.cpp | 54 ++--- source/listing_7.21.cpp | 94 ++++---- source/listing_7.3.cpp | 48 ++-- source/listing_7.4.cpp | 35 ++- source/listing_7.5.cpp | 88 ++++--- source/listing_7.6.cpp | 52 ++--- source/listing_7.7.cpp | 69 +++--- source/listing_7.8.cpp | 72 +++--- source/listing_7.9.cpp | 50 ++-- source/listing_8.1.cpp | 164 +++++++------ source/listing_8.10.cpp | 74 +++--- source/listing_8.11.cpp | 166 +++++++------- source/listing_8.12.cpp | 40 ++-- source/listing_8.13.cpp | 167 +++++++------- source/listing_8.2.cpp | 71 +++--- source/listing_8.3.cpp | 83 ++++--- source/listing_8.4.cpp | 68 +++--- source/listing_8.5.cpp | 34 ++- source/listing_8.6.cpp | 76 +++---- source/listing_8.7.cpp | 65 +++--- source/listing_8.8.cpp | 36 ++- source/listing_8.9.cpp | 130 +++++------ source/listing_9.1.cpp | 81 +++---- source/listing_9.10.cpp | 15 +- source/listing_9.11.cpp | 85 ++++--- source/listing_9.12.cpp | 124 +++++----- source/listing_9.13.cpp | 49 ++-- source/listing_9.2.cpp | 91 ++++---- source/listing_9.3.cpp | 49 ++-- source/listing_9.4.cpp | 19 +- source/listing_9.5.cpp | 95 ++++---- source/listing_9.6.cpp | 93 ++++---- source/listing_9.7.cpp | 83 ++++--- source/listing_9.8.cpp | 180 +++++++-------- source/listing_9.9.cpp | 46 ++-- source/listing_a.1.cpp | 30 +-- source/listing_a.2.cpp | 24 +- source/listing_a.3.cpp | 29 +-- source/listing_a.4.cpp | 7 +- source/listing_c.1.cpp | 71 +++--- source/listing_c.10.cpp | 95 ++++---- source/listing_c.2.cpp | 38 ++-- source/listing_c.3.cpp | 25 +- source/listing_c.4.cpp | 102 ++++----- source/listing_c.5.cpp | 124 +++++----- source/listing_c.6.cpp | 194 +++++++--------- source/listing_c.7.cpp | 299 ++++++++++-------------- source/listing_c.8.cpp | 107 ++++----- source/listing_c.9.cpp | 187 ++++++--------- 149 files changed, 5974 insertions(+), 6287 deletions(-) create mode 100644 .clang-format create mode 100644 .cproject create mode 100644 .project create mode 100644 .settings/language.settings.xml diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..3ed6866 --- /dev/null +++ b/.clang-format @@ -0,0 +1,104 @@ +Language: Cpp +# BasedOnStyle: Google +AccessModifierOffset: -2 +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: true +AlignConsecutiveDeclarations: false +AlignEscapedNewlines: Right +AlignOperands: true +AlignTrailingComments: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: Inline +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: true +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: TopLevelDefinitions +AlwaysBreakBeforeMultilineStrings: true +AlwaysBreakTemplateDeclarations: true +BinPackArguments: false +BinPackParameters: false +BreakBeforeBraces : Custom +BraceWrapping: + AfterClass: false + AfterControlStatement: false + AfterEnum: false + AfterFunction: true + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + BeforeCatch: true + BeforeElse: true + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true +BreakBeforeBinaryOperators: None +BreakBeforeInheritanceComma: true +BreakBeforeTernaryOperators: true +BreakConstructorInitializers: BeforeColon +BreakAfterJavaFieldAnnotations: false +BreakStringLiterals: true +ColumnLimit: 80 +CommentPragmas: '^ IWYU pragma:' +CompactNamespaces: false +ConstructorInitializerAllOnOneLineOrOnePerLine: true +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DerivePointerAlignment: false +DisableFormat: false +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: true +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH +IncludeCategories: + - Regex: '^<.*\.h>' + Priority: 1 + - Regex: '^<.*' + Priority: 2 + - Regex: '.*' + Priority: 3 +IncludeIsMainRegex: '([-_](test|unittest))?$' +IndentCaseLabels: false +IndentWidth: 2 +IndentWrappedFunctionNames: false +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLinesAtTheStartOfBlocks: false +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCBlockIndentWidth: 2 +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: false +PenaltyBreakAssignment: 2 +PenaltyBreakBeforeFirstCallParameter: 1 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 200 +PointerAlignment: Left +ReflowComments: true +SortIncludes: true +SortUsingDeclarations: true +SpaceAfterCStyleCast: true +SpaceAfterTemplateKeyword: true +SpaceBeforeAssignmentOperators: true +SpaceBeforeParens: ControlStatements +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 2 +SpacesInAngles: false +SpacesInContainerLiterals: false +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: Cpp11 +TabWidth: 2 +UseTab: Never diff --git a/.cproject b/.cproject new file mode 100644 index 0000000..a2780b7 --- /dev/null +++ b/.cproject @@ -0,0 +1,114 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.project b/.project new file mode 100644 index 0000000..4a9287f --- /dev/null +++ b/.project @@ -0,0 +1,27 @@ + + + concurrency-in-action + + + + + + org.eclipse.cdt.managedbuilder.core.genmakebuilder + clean,full,incremental, + + + + + org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder + full,incremental, + + + + + + org.eclipse.cdt.core.cnature + org.eclipse.cdt.core.ccnature + org.eclipse.cdt.managedbuilder.core.managedBuildNature + org.eclipse.cdt.managedbuilder.core.ScannerConfigNature + + diff --git a/.settings/language.settings.xml b/.settings/language.settings.xml new file mode 100644 index 0000000..8237590 --- /dev/null +++ b/.settings/language.settings.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ch1/hello.cpp b/ch1/hello.cpp index 50378c1..9729041 100644 --- a/ch1/hello.cpp +++ b/ch1/hello.cpp @@ -1,18 +1,17 @@ #include #include -void hello() +void +hello() { - std::cout << "Hello Concurrent World\n"; + std::cout << "Hello Concurrent World\n"; } -int main() +int +main() { - //boost::thread t([]() - std::thread t([]() - { - std::cout << "Hello Concurrent World\n"; - }); + // boost::thread t([]() + std::thread t([]() { std::cout << "Hello Concurrent World\n"; }); - t.join(); + t.join(); } diff --git a/ch2/accumulate.cpp b/ch2/accumulate.cpp index 372f1fe..f3d5cb2 100644 --- a/ch2/accumulate.cpp +++ b/ch2/accumulate.cpp @@ -1,69 +1,69 @@ #include #include #include -#include +#include // std::accumulate #include -#include // std::accumulate +#include template -struct accumulate_block -{ - void operator()(Iterator first, Iterator last, T& result) - { - result = std::accumulate(first,last,result); - } +struct accumulate_block { + void operator()(Iterator first, Iterator last, T& result) + { + result = std::accumulate(first, last, result); + } }; template -T parallel_accumulate(Iterator first, Iterator last, T init) +T +parallel_accumulate(Iterator first, Iterator last, T init) { - unsigned long const length = std::distance(first,last); + unsigned long const length = std::distance(first, last); - if (!length) return init; + if (!length) + return init; - unsigned long const min_per_thread = 25; - unsigned long const max_threads = - (length+min_per_thread-1)/min_per_thread; + unsigned long const min_per_thread = 25; + unsigned long const max_threads = + (length + min_per_thread - 1) / min_per_thread; - unsigned long const hardware_threads = - std::thread::hardware_concurrency(); + unsigned long const hardware_threads = std::thread::hardware_concurrency(); - unsigned long const num_threads = - std::min(hardware_threads != 0 ? hardware_threads:2, max_threads); + unsigned long const num_threads = + std::min(hardware_threads != 0 ? hardware_threads : 2, max_threads); - unsigned long const block_size = length / num_threads; + unsigned long const block_size = length / num_threads; - std::vector results(num_threads); - std::vector threads(num_threads-1); + std::vector results(num_threads); + std::vector threads(num_threads - 1); - Iterator block_start = first; - for (unsigned long i = 0; i < (num_threads-1); ++i) - { - Iterator block_end = block_start; - std::advance(block_end,block_size); - threads[i] = std::thread( - accumulate_block(), - block_start,block_end,std::ref(results[i])); - block_start = block_end; - } - accumulate_block::iterator,int>()( - block_start,last,results[num_threads-1]); + Iterator block_start = first; + for (unsigned long i = 0; i < (num_threads - 1); ++i) { + Iterator block_end = block_start; + std::advance(block_end, block_size); + threads[i] = std::thread(accumulate_block(), + block_start, + block_end, + std::ref(results[i])); + block_start = block_end; + } + accumulate_block::iterator, int>()( + block_start, last, results[num_threads - 1]); - std::for_each(threads.begin(),threads.end(), - std::mem_fn(&std::thread::join)); + std::for_each( + threads.begin(), threads.end(), std::mem_fn(&std::thread::join)); - return std::accumulate(results.begin(),results.end(),init); + return std::accumulate(results.begin(), results.end(), init); } -int main() +int +main() { - std::vector numbers(50); - for (int i = 0; i < 50; ++i) { - numbers[i] = i; - } - int result = parallel_accumulate::iterator,int> - (numbers.begin(),numbers.end(),0); + std::vector numbers(50); + for (int i = 0; i < 50; ++i) { + numbers[i] = i; + } + int result = parallel_accumulate::iterator, int>( + numbers.begin(), numbers.end(), 0); - std::cout << "result: " << result << std::endl; + std::cout << "result: " << result << std::endl; } - diff --git a/ch3/hierarchical.cpp b/ch3/hierarchical.cpp index 4e4f2a2..5bad26e 100644 --- a/ch3/hierarchical.cpp +++ b/ch3/hierarchical.cpp @@ -1,57 +1,56 @@ +#include #include #include -#include -class hierarchical_mutex -{ - std::mutex internal_mutex; - unsigned long const hierarchy_value; - unsigned long previous_hierarchy_value; - static thread_local unsigned long this_thread_hierarchy_value; +class hierarchical_mutex { + std::mutex internal_mutex; + unsigned long const hierarchy_value; + unsigned long previous_hierarchy_value; + static thread_local unsigned long this_thread_hierarchy_value; - void check_for_hierarchy_violation() - { - if(this_thread_hierarchy_value <= hierarchy_value) - { - throw std::logic_error("mutex hierarchy violated"); - } - } - void update_hierarchy_value() - { - previous_hierarchy_value=this_thread_hierarchy_value; - this_thread_hierarchy_value=hierarchy_value; + void check_for_hierarchy_violation() + { + if (this_thread_hierarchy_value <= hierarchy_value) { + throw std::logic_error("mutex hierarchy violated"); } + } + void update_hierarchy_value() + { + previous_hierarchy_value = this_thread_hierarchy_value; + this_thread_hierarchy_value = hierarchy_value; + } + public: - explicit hierarchical_mutex(unsigned long value): - hierarchy_value(value), - previous_hierarchy_value(0) - {} - void lock() - { - check_for_hierarchy_violation(); - internal_mutex.lock(); - update_hierarchy_value(); - } - void unlock() - { - this_thread_hierarchy_value=previous_hierarchy_value; - internal_mutex.unlock(); - } - bool try_lock() - { - check_for_hierarchy_violation(); - if(!internal_mutex.try_lock()) - return false; - update_hierarchy_value(); - return true; - } + explicit hierarchical_mutex(unsigned long value) + : hierarchy_value(value), previous_hierarchy_value(0) + { + } + void lock() + { + check_for_hierarchy_violation(); + internal_mutex.lock(); + update_hierarchy_value(); + } + void unlock() + { + this_thread_hierarchy_value = previous_hierarchy_value; + internal_mutex.unlock(); + } + bool try_lock() + { + check_for_hierarchy_violation(); + if (!internal_mutex.try_lock()) + return false; + update_hierarchy_value(); + return true; + } }; -thread_local unsigned long - hierarchical_mutex::this_thread_hierarchy_value(ULONG_MAX); +thread_local unsigned long hierarchical_mutex::this_thread_hierarchy_value( + ULONG_MAX); -int main() +int +main() { - hierarchical_mutex m1(42); - hierarchical_mutex m2(2000); - + hierarchical_mutex m1(42); + hierarchical_mutex m2(2000); } diff --git a/ch3/stack.cpp b/ch3/stack.cpp index 5afbcf7..23a0150 100644 --- a/ch3/stack.cpp +++ b/ch3/stack.cpp @@ -1,68 +1,64 @@ #include -#include -#include #include +#include +#include -struct empty_stack: std::exception -{ - const char* what() const throw() - { - return "empty stack"; - } - +struct empty_stack : std::exception { + const char* what() const throw() { return "empty stack"; } }; -template -class threadsafe_stack -{ +template +class threadsafe_stack { private: - std::stack data; - mutable std::mutex m; -public: - threadsafe_stack(){} - threadsafe_stack(const threadsafe_stack& other) - { - std::lock_guard lock(other.m); - data=other.data; - } - threadsafe_stack& operator=(const threadsafe_stack&) = delete; + std::stack data; + mutable std::mutex m; - void push(T new_value) - { - std::lock_guard lock(m); - data.push(new_value); - } - std::shared_ptr pop() - { - std::lock_guard lock(m); - if(data.empty()) throw empty_stack(); - std::shared_ptr const res(std::make_shared(data.top())); - data.pop(); - return res; - } - void pop(T& value) - { - std::lock_guard lock(m); - if(data.empty()) throw empty_stack(); - value=data.top(); - data.pop(); - } - bool empty() const - { - std::lock_guard lock(m); - return data.empty(); - } +public: + threadsafe_stack() {} + threadsafe_stack(const threadsafe_stack& other) + { + std::lock_guard lock(other.m); + data = other.data; + } + threadsafe_stack& operator=(const threadsafe_stack&) = delete; + + void push(T new_value) + { + std::lock_guard lock(m); + data.push(new_value); + } + std::shared_ptr pop() + { + std::lock_guard lock(m); + if (data.empty()) + throw empty_stack(); + std::shared_ptr const res(std::make_shared(data.top())); + data.pop(); + return res; + } + void pop(T& value) + { + std::lock_guard lock(m); + if (data.empty()) + throw empty_stack(); + value = data.top(); + data.pop(); + } + bool empty() const + { + std::lock_guard lock(m); + return data.empty(); + } }; -int main() +int +main() { - threadsafe_stack si; - si.push(5); - si.pop(); - if(!si.empty()) - { - int x; - si.pop(x); - } - + threadsafe_stack si; + si.push(5); + si.pop(); + if (!si.empty()) { + int x; + si.pop(x); + } } diff --git a/ch4/queue.cpp b/ch4/queue.cpp index d8a7e46..9ca9de9 100644 --- a/ch4/queue.cpp +++ b/ch4/queue.cpp @@ -1,104 +1,105 @@ -#include +#include #include -#include -#include +#include #include #include -#include +#include +#include template -class queue -{ - private: - mutable std::mutex mut; - std::queue data_queue; - std::condition_variable data_cond; +class queue { +private: + mutable std::mutex mut; + std::queue data_queue; + std::condition_variable data_cond; - public: - queue(){} +public: + queue() {} - queue(const queue& other) - { - std::lock_guard lk(other.mut); - data_queue = other.data_queue; + queue(const queue& other) + { + std::lock_guard lk(other.mut); + data_queue = other.data_queue; + } + + void push(T new_value) + { + std::lock_guard lk(mut); + data_queue.push(new_value); + data_cond.notify_one(); + } + + void wait_and_pop(T& value) + { + std::unique_lock lk(mut); + data_cond.wait(lk, [this] { return !data_queue.empty(); }); + value = data_queue.front(); + data_queue.pop(); + } + + std::shared_ptr wait_and_pop() + { + std::unique_lock lk(mut); + data_cond.wait(lk, [this] { return !data_queue.empty(); }); + std::shared_ptr res(std::make_shared(data_queue.front())); + data_queue.pop(); + return res; + } + + bool try_pop(T& value) + { + std::lock_guard lk(mut); + if (data_queue.empty()) { + return false; } + value = data_queue.front(); + data_queue.pop(); + return true; + } - void push(T new_value) - { - std::lock_guard lk(mut); - data_queue.push(new_value); - data_cond.notify_one(); + std::shared_ptr try_pop() + { + std::lock_guard lk(mut); + if (data_queue.empty()) { + return std::shared_ptr(); } + std::shared_ptr res(std::make_shared(data_queue.front())); + data_queue.pop(); + return res; + } - void wait_and_pop(T& value) - { - std::unique_lock lk(mut); - data_cond.wait(lk, [this]{return !data_queue.empty();}); - value = data_queue.front(); - data_queue.pop(); - } - - std::shared_ptr wait_and_pop() - { - std::unique_lock lk(mut); - data_cond.wait(lk, [this]{return !data_queue.empty();}); - std::shared_ptr res(std::make_shared(data_queue.front())); - data_queue.pop(); - return res; - } - - bool try_pop(T& value) - { - std::lock_guard lk(mut); - if (data_queue.empty()) { - return false; - } - value = data_queue.front(); - data_queue.pop(); - return true; - } - - std::shared_ptr try_pop() - { - std::lock_guard lk(mut); - if (data_queue.empty()) { - return std::shared_ptr(); - } - std::shared_ptr res(std::make_shared(data_queue.front())); - data_queue.pop(); - return res; - } - - bool empty() const - { - std::lock_guard lk(mut); - return data_queue.empty(); - } + bool empty() const + { + std::lock_guard lk(mut); + return data_queue.empty(); + } }; -void push(queue* q) +void +push(queue* q) { - for (int i = 0; i < 10; ++i) { - //std::cout << "pushing " << i << std::endl; - printf("pushing %d\n", i); - q->push(i); - } + for (int i = 0; i < 10; ++i) { + // std::cout << "pushing " << i << std::endl; + printf("pushing %d\n", i); + q->push(i); + } } -void pop(queue* q) +void +pop(queue* q) { - for (int i = 0; i < 10; ++i) { - printf("poping %d\n", *q->wait_and_pop()); - } -} - -int main() -{ - queue q; - std::thread t1(push,&q); - std::thread t2(pop,&q); - t1.join(); - t2.join(); - return 0; + for (int i = 0; i < 10; ++i) { + printf("poping %d\n", *q->wait_and_pop()); + } } +int +main() +{ + queue q; + std::thread t1(push, &q); + std::thread t2(pop, &q); + t1.join(); + t2.join(); + return 0; +} diff --git a/ch4/quicksort.cpp b/ch4/quicksort.cpp index 1eab835..bca6d01 100644 --- a/ch4/quicksort.cpp +++ b/ch4/quicksort.cpp @@ -1,74 +1,70 @@ -#include -#include -#include -#include -#include #include +#include #include +#include +#include +#include +#include -std::ostream& operator<<(std::ostream& ostr, const std::list& list) +std::ostream& +operator<<(std::ostream& ostr, const std::list& list) { - for (auto &i : list) { - ostr << " " << i; - } - return ostr; + for (auto& i : list) { + ostr << " " << i; + } + return ostr; } -template -std::list sequential_quick_sort(std::list input) +template +std::list +sequential_quick_sort(std::list input) { - if(input.empty()) - { - return input; - } - std::list result; - result.splice(result.begin(),input,input.begin()); - T const& pivot=*result.begin(); - auto divide_point=std::partition(input.begin(),input.end(), - [&](T const& t){return t lower_part; - lower_part.splice(lower_part.end(),input,input.begin(), - divide_point); - auto new_lower( - sequential_quick_sort(std::move(lower_part))); - auto new_higher( - sequential_quick_sort(std::move(input))); - result.splice(result.end(),new_higher); - result.splice(result.begin(),new_lower); - return result; + if (input.empty()) { + return input; + } + std::list result; + result.splice(result.begin(), input, input.begin()); + T const& pivot = *result.begin(); + auto divide_point = std::partition( + input.begin(), input.end(), [&](T const& t) { return t < pivot; }); + std::list lower_part; + lower_part.splice(lower_part.end(), input, input.begin(), divide_point); + auto new_lower(sequential_quick_sort(std::move(lower_part))); + auto new_higher(sequential_quick_sort(std::move(input))); + result.splice(result.end(), new_higher); + result.splice(result.begin(), new_lower); + return result; } -template -std::list parallel_quick_sort(std::list input) +template +std::list +parallel_quick_sort(std::list input) { - if(input.empty()) - { - return input; - } - std::list result; - result.splice(result.begin(),input,input.begin()); - T const& pivot=*result.begin(); - auto divide_point=std::partition(input.begin(),input.end(), - [&](T const& t){return t lower_part; - lower_part.splice(lower_part.end(),input,input.begin(), - divide_point); - std::future > new_lower( - std::async(¶llel_quick_sort,std::move(lower_part))); - auto new_higher( - parallel_quick_sort(std::move(input))); - result.splice(result.end(),new_higher); - result.splice(result.begin(),new_lower.get()); - return result; + if (input.empty()) { + return input; + } + std::list result; + result.splice(result.begin(), input, input.begin()); + T const& pivot = *result.begin(); + auto divide_point = std::partition( + input.begin(), input.end(), [&](T const& t) { return t < pivot; }); + std::list lower_part; + lower_part.splice(lower_part.end(), input, input.begin(), divide_point); + std::future> new_lower( + std::async(¶llel_quick_sort, std::move(lower_part))); + auto new_higher(parallel_quick_sort(std::move(input))); + result.splice(result.end(), new_higher); + result.splice(result.begin(), new_lower.get()); + return result; } -int main() +int +main() { - std::list list1 = {4, 2, 1, 5, 8, 9, 7}; - std::list sorted1 = sequential_quick_sort(list1); - std::list sorted2 = parallel_quick_sort(list1); - std::cout << "sorted1: " << sorted1 << std::endl; - std::cout << "sorted2: " << sorted2 << std::endl; - return 0; + std::list list1 = {4, 2, 1, 5, 8, 9, 7}; + std::list sorted1 = sequential_quick_sort(list1); + std::list sorted2 = parallel_quick_sort(list1); + std::cout << "sorted1: " << sorted1 << std::endl; + std::cout << "sorted2: " << sorted2 << std::endl; + return 0; } - diff --git a/ch6/list.cpp b/ch6/list.cpp index 8f8a0b4..c641eee 100644 --- a/ch6/list.cpp +++ b/ch6/list.cpp @@ -1,126 +1,115 @@ -#include -#include -#include #include +#include +#include +#include template -class list -{ - struct node - { - std::mutex m; - std::shared_ptr data; - std::unique_ptr next; +class list { + struct node { + std::mutex m; + std::shared_ptr data; + std::unique_ptr next; - node() - : next() - {} - - node(T const& value) - : data(std::make_shared(value)) - {} - }; + node() : next() {} - node head; + node(T const& value) : data(std::make_shared(value)) {} + }; - public: - list() - {} + node head; - ~list() - { - remove_if([](T const&){return true;}); +public: + list() {} + + ~list() + { + remove_if([](T const&) { return true; }); + } + + list(list const& other) = delete; + list& operator=(list const& other) = delete; + + void push_front(T const& value) + { + std::unique_ptr new_node(new node(value)); + std::lock_guard lk(head.m); + new_node->next = std::move(head.next); + head.next = std::move(new_node); + } + + template + void for_each(Function f) + { + node* current = &head; + std::unique_lock lk(head.m); + while (node* const next = current->next.get()) { + std::unique_lock next_lk(next->m); + lk.unlock(); + f(*next->data); + current = next; + lk = std::move(next_lk); } + } - list(list const& other) = delete; - list& operator=(list const& other) = delete; - - void push_front(T const& value) - { - std::unique_ptr new_node(new node(value)); - std::lock_guard lk(head.m); - new_node->next = std::move(head.next); - head.next = std::move(new_node); + template + std::shared_ptr find_first_of(Predicate p) + { + node* current = &head; + std::unique_lock lk(head.m); + while (node* const next = current->next.get()) { + std::unique_lock next_lk(next->m); + lk.unlock(); + if (p(*next->data)) { + return next->data; + } + current = next; + lk = std::move(next_lk); } + return std::shared_ptr(); + } - template - void for_each(Function f) - { - node* current = &head; - std::unique_lock lk(head.m); - while (node* const next = current->next.get()) - { - std::unique_lock next_lk(next->m); - lk.unlock(); - f(*next->data); - current = next; - lk = std::move(next_lk); - } - } - - template - std::shared_ptr find_first_of(Predicate p) - { - node *current = &head; - std::unique_lock lk(head.m); - while (node* const next = current->next.get()) - { - std::unique_lock next_lk(next->m); - lk.unlock(); - if (p(*next->data)) - { - return next->data; - } - current = next; - lk = std::move(next_lk); - } - return std::shared_ptr(); - } - - template - void remove_if(Predicate p) - { - node *current = &head; - std::unique_lock lk(head.m); - while (node* const next = current->next.get()) - { - std::unique_lock next_lk(next->m); - if (p(*next->data)) - { - std::unique_ptr old_next = std::move(current->next); - current->next = std::move(next->next); - next_lk.unlock(); - } - else - { - lk.unlock(); - current = next; - lk = std::move(next_lk); - } - } + template + void remove_if(Predicate p) + { + node* current = &head; + std::unique_lock lk(head.m); + while (node* const next = current->next.get()) { + std::unique_lock next_lk(next->m); + if (p(*next->data)) { + std::unique_ptr old_next = std::move(current->next); + current->next = std::move(next->next); + next_lk.unlock(); + } + else { + lk.unlock(); + current = next; + lk = std::move(next_lk); + } } + } }; -void push(list* l) +void +push(list* l) { - for (int i = 0; i < 10; ++i) { - printf("pushing %d\n", i); - l->push_front(i); - } + for (int i = 0; i < 10; ++i) { + printf("pushing %d\n", i); + l->push_front(i); + } } -void visit(int i) +void +visit(int i) { - printf("visit %d\n", i); -} - -int main() -{ - list l; - std::thread t(push,&l); - sleep(1); - l.for_each(visit); - t.join(); - return 0; + printf("visit %d\n", i); } +int +main() +{ + list l; + std::thread t(push, &l); + sleep(1); + l.for_each(visit); + t.join(); + return 0; +} diff --git a/ch6/lookuptable.cpp b/ch6/lookuptable.cpp index fe0e672..218c646 100644 --- a/ch6/lookuptable.cpp +++ b/ch6/lookuptable.cpp @@ -1,133 +1,122 @@ +#include #include +#include +#include #include #include -#include -#include -#include #include -template > -class lookup_table -{ +template > +class lookup_table { +private: + class bucket_type { private: - class bucket_type + typedef std::pair bucket_value; + typedef std::list bucket_data; + typedef typename bucket_data::iterator bucket_iterator; + + bucket_data data; + mutable boost::shared_mutex mutex; + + bucket_iterator find_entry_for(Key const& key) const { - private: - typedef std::pair bucket_value; - typedef std::list bucket_data; - typedef typename bucket_data::iterator bucket_iterator; - - bucket_data data; - mutable boost::shared_mutex mutex; - - bucket_iterator find_entry_for(Key const& key) const - { - return std::find_if(data.begin(), data.end(), - [&](bucket_value const& item) - {return item.first == key;}); - } - - public: - Value value_for(Key const& key, Value const& default_value) const - { - boost::shared_lock lock(mutex); - bucket_iterator const found_entry = find_entry_for(key); - return (found_entry == data.end()) ? - default_value : found_entry->second; - } - - void add_or_update_mapping(Key const& key, Value const& value) - { - std::unique_lock lock(mutex); - bucket_iterator const found_entry = find_entry_for(key); - if (found_entry == data.end()) { - data.push_back(bucket_value(key,value)); - } - else { - found_entry->second = value; - } - } - - void remove_mapping(Key const& key) - { - std::unique_lock lock(mutex); - bucket_iterator const found_entry = find_entry_for(key); - if (found_entry != data.end()) { - data.erase(found_entry); - } - } - }; - - std::vector > buckets; - Hash hasher; - - bucket_type& get_bucket(Key const& key) const - { - const std::size_t bucket_index = hasher(key) % buckets.size(); - return *buckets[bucket_index]; + return std::find_if( + data.begin(), data.end(), [&](bucket_value const& item) { + return item.first == key; + }); } public: - typedef Key key_type; - typedef Value mapped_type; - typedef Hash hash_type; - - lookup_table(unsigned num_buckets = 19, const Hash& hasher_ = Hash()) - : buckets(num_buckets) - , hasher(hasher_) + Value value_for(Key const& key, Value const& default_value) const { - for (unsigned i = 0; i < num_buckets; ++i) - { - buckets[i].reset(new bucket_type); - } + boost::shared_lock lock(mutex); + bucket_iterator const found_entry = find_entry_for(key); + return (found_entry == data.end()) ? default_value : found_entry->second; } - lookup_table(const lookup_table& other) = delete; - lookup_table& operator=(const lookup_table& other) = delete; - - Value value_for(Key const& key, - Value const& default_value = Value()) const + void add_or_update_mapping(Key const& key, Value const& value) { - return get_bucket(key).value_for(key, default_value); + std::unique_lock lock(mutex); + bucket_iterator const found_entry = find_entry_for(key); + if (found_entry == data.end()) { + data.push_back(bucket_value(key, value)); + } + else { + found_entry->second = value; + } } - void add_or_update_mapping(const Key& key, const Value& value) + void remove_mapping(Key const& key) { - get_bucket(key).add_or_update_mapping(key, value); + std::unique_lock lock(mutex); + bucket_iterator const found_entry = find_entry_for(key); + if (found_entry != data.end()) { + data.erase(found_entry); + } } + }; - void remove_mapping(const Key& key) - { - get_bucket(key).remove_mapping(key); - } + std::vector> buckets; + Hash hasher; - std::map get_map() const - { - std::vector > locks; - for (unsigned i = 0; i < buckets.size(); ++i) - { - locks.push_back(boost::unique_lock( - buckets[i].mutex)); - } - std::map res; - for (unsigned i = 0; i < buckets.size(); ++i) - { - for (typename bucket_type::bucket_iterator it = buckets[i].data.begin(); - it != buckets[i].data.end(); - ++it) - { - res.insert(*it); - } - } - return res; + bucket_type& get_bucket(Key const& key) const + { + const std::size_t bucket_index = hasher(key) % buckets.size(); + return *buckets[bucket_index]; + } + +public: + typedef Key key_type; + typedef Value mapped_type; + typedef Hash hash_type; + + lookup_table(unsigned num_buckets = 19, const Hash& hasher_ = Hash()) + : buckets(num_buckets), hasher(hasher_) + { + for (unsigned i = 0; i < num_buckets; ++i) { + buckets[i].reset(new bucket_type); } + } + + lookup_table(const lookup_table& other) = delete; + lookup_table& operator=(const lookup_table& other) = delete; + + Value value_for(Key const& key, Value const& default_value = Value()) const + { + return get_bucket(key).value_for(key, default_value); + } + + void add_or_update_mapping(const Key& key, const Value& value) + { + get_bucket(key).add_or_update_mapping(key, value); + } + + void remove_mapping(const Key& key) { get_bucket(key).remove_mapping(key); } + + std::map get_map() const + { + std::vector> locks; + for (unsigned i = 0; i < buckets.size(); ++i) { + locks.push_back( + boost::unique_lock(buckets[i].mutex)); + } + std::map res; + for (unsigned i = 0; i < buckets.size(); ++i) { + for (typename bucket_type::bucket_iterator it = buckets[i].data.begin(); + it != buckets[i].data.end(); + ++it) { + res.insert(*it); + } + } + return res; + } }; -int main() +int +main() { - lookup_table t; - t.add_or_update_mapping(1,"hello"); - std::cout << "value for 1 is " << t.value_for(1) << std::endl; - return 0; + lookup_table t; + t.add_or_update_mapping(1, "hello"); + std::cout << "value for 1 is " << t.value_for(1) << std::endl; + return 0; } - diff --git a/ch6/queue.cpp b/ch6/queue.cpp index d2cd772..fb572ff 100644 --- a/ch6/queue.cpp +++ b/ch6/queue.cpp @@ -1,112 +1,113 @@ -#include +#include #include -#include -#include +#include #include #include -#include +#include +#include template -class queue -{ - private: - mutable std::mutex mut; - std::queue > data_queue; - std::condition_variable data_cond; +class queue { +private: + mutable std::mutex mut; + std::queue> data_queue; + std::condition_variable data_cond; - public: - queue(){} +public: + queue() {} - queue(const queue& other) - { - std::lock_guard lk(other.mut); - data_queue = other.data_queue; + queue(const queue& other) + { + std::lock_guard lk(other.mut); + data_queue = other.data_queue; + } + + void push(T new_value) + { + std::shared_ptr data(new T(new_value)); + std::lock_guard lk(mut); + data_queue.push(data); + data_cond.notify_one(); + } + + void wait_and_pop(T& value) + { + std::unique_lock lk(mut); + data_cond.wait(lk, [&] { return !data_queue.empty(); }); + /* + while (data_queue.empty()) { + data_cond.wait(lk); } + */ + value = *data_queue.front(); + data_queue.pop(); + } - void push(T new_value) - { - std::shared_ptr data(new T(new_value)); - std::lock_guard lk(mut); - data_queue.push(data); - data_cond.notify_one(); + std::shared_ptr wait_and_pop() + { + std::unique_lock lk(mut); + data_cond.wait(lk, [&] { return !data_queue.empty(); }); + /* + while (data_queue.empty()) { + data_cond.wait(lk); } + */ + std::shared_ptr res = data_queue.front(); + data_queue.pop(); + return res; + } - void wait_and_pop(T& value) - { - std::unique_lock lk(mut); - data_cond.wait(lk, [&]{return !data_queue.empty();}); - /* - while (data_queue.empty()) { - data_cond.wait(lk); - } - */ - value = *data_queue.front(); - data_queue.pop(); - } + bool try_pop(T& value) + { + std::lock_guard lk(mut); + if (data_queue.empty()) + return false; + value = *data_queue.front(); + data_queue.pop(); + } - std::shared_ptr wait_and_pop() - { - std::unique_lock lk(mut); - data_cond.wait(lk, [&]{return !data_queue.empty();}); - /* - while (data_queue.empty()) { - data_cond.wait(lk); - } - */ - std::shared_ptr res = data_queue.front(); - data_queue.pop(); - return res; - } + std::shared_ptr try_pop() + { + std::lock_guard lk(mut); + if (data_queue.empty()) + return std::shared_ptr(); + std::shared_ptr res = data_queue.front(); + data_queue.pop(); + return res; + } - bool try_pop(T& value) - { - std::lock_guard lk(mut); - if (data_queue.empty()) - return false; - value = *data_queue.front(); - data_queue.pop(); - } - - std::shared_ptr try_pop() - { - std::lock_guard lk(mut); - if (data_queue.empty()) - return std::shared_ptr(); - std::shared_ptr res = data_queue.front(); - data_queue.pop(); - return res; - } - - bool empty() const - { - std::lock_guard lk(mut); - return data_queue.empty(); - } + bool empty() const + { + std::lock_guard lk(mut); + return data_queue.empty(); + } }; -void push(queue* q) +void +push(queue* q) { - for (int i = 0; i < 10; ++i) { - //std::cout << "pushing " << i << std::endl; - printf("pushing %d\n", i); - q->push(i); - } + for (int i = 0; i < 10; ++i) { + // std::cout << "pushing " << i << std::endl; + printf("pushing %d\n", i); + q->push(i); + } } -void pop(queue* q) +void +pop(queue* q) { - for (int i = 0; i < 10; ++i) { - printf("poping %d\n", *q->wait_and_pop()); - } -} - -int main() -{ - queue q; - std::thread t1(push,&q); - std::thread t2(pop,&q); - t1.join(); - t2.join(); - return 0; + for (int i = 0; i < 10; ++i) { + printf("poping %d\n", *q->wait_and_pop()); + } } +int +main() +{ + queue q; + std::thread t1(push, &q); + std::thread t2(pop, &q); + t1.join(); + t2.join(); + return 0; +} diff --git a/ch6/queuelist.cpp b/ch6/queuelist.cpp index 9a23bfa..a9cd061 100644 --- a/ch6/queuelist.cpp +++ b/ch6/queuelist.cpp @@ -1,94 +1,93 @@ #include -#include #include -#include #include +#include +#include template -class queue -{ - private: - struct node - { - std::shared_ptr data; - std::unique_ptr next; - }; +class queue { +private: + struct node { + std::shared_ptr data; + std::unique_ptr next; + }; - std::mutex head_mutex; - std::unique_ptr head; - std::mutex tail_mutex; - node *tail; + std::mutex head_mutex; + std::unique_ptr head; + std::mutex tail_mutex; + node* tail; - node *get_tail() - { - std::lock_guard tail_lock(tail_mutex); - return tail; + node* get_tail() + { + std::lock_guard tail_lock(tail_mutex); + return tail; + } + + std::unique_ptr pop_head() + { + std::lock_guard head_lock(head_mutex); + if (head.get() == get_tail()) { + return nullptr; } + std::unique_ptr old_head = std::move(head); + head = std::move(old_head->next); + return old_head; + } - std::unique_ptr pop_head() - { - std::lock_guard head_lock(head_mutex); - if (head.get() == get_tail()) { - return nullptr; - } - std::unique_ptr old_head = std::move(head); - head = std::move(old_head->next); - return old_head; - } +public: + queue() : head(new node), tail(head.get()) {} - public: - queue():head(new node),tail(head.get()) - {} + queue(const queue& other) = delete; + queue& operator=(const queue& other) = delete; - queue(const queue& other) = delete; - queue& operator=(const queue& other) = delete; + std::shared_ptr try_pop() + { + std::unique_ptr old_head = pop_head(); + return old_head ? old_head->data : std::shared_ptr(); + } - std::shared_ptr try_pop() - { - std::unique_ptr old_head = pop_head(); - return old_head ? old_head->data : std::shared_ptr(); - } - - void push(T new_value) - { - std::shared_ptr new_data( - std::make_shared(std::move(new_value))); - std::unique_ptr p(new node); - node *const new_tail = p.get(); - std::lock_guard tail_lock(tail_mutex); - tail->data = new_data; - tail->next = std::move(p); - tail = new_tail; - } + void push(T new_value) + { + std::shared_ptr new_data(std::make_shared(std::move(new_value))); + std::unique_ptr p(new node); + node* const new_tail = p.get(); + std::lock_guard tail_lock(tail_mutex); + tail->data = new_data; + tail->next = std::move(p); + tail = new_tail; + } }; -void push(queue* q) +void +push(queue* q) { - for (int i = 0; i < 10; ++i) { - printf("pushing %d\n", i); - q->push(i); + for (int i = 0; i < 10; ++i) { + printf("pushing %d\n", i); + q->push(i); + } +} + +void +pop(queue* q) +{ + int i = 0; + while (true) { + if (std::shared_ptr p = q->try_pop()) { + printf("poping %d\n", *p); + ++i; } + if (i == 10) + break; + } } -void pop(queue* q) +int +main() { - int i = 0; - while (true) { - if (std::shared_ptr p = q->try_pop()) { - printf("poping %d\n", *p); - ++i; - } - if (i == 10) break; - } + queue q; + std::thread th1(push, &q); + std::thread th2(pop, &q); + th1.join(); + th2.join(); + return 0; } - -int main() -{ - queue q; - std::thread th1(push,&q); - std::thread th2(pop,&q); - th1.join(); - th2.join(); - return 0; -} - diff --git a/ch6/queuelist2.cpp b/ch6/queuelist2.cpp index 52c6ee5..79ae9e5 100644 --- a/ch6/queuelist2.cpp +++ b/ch6/queuelist2.cpp @@ -1,154 +1,151 @@ -#include -#include -#include -#include -#include #include +#include +#include +#include +#include +#include template -class queue -{ - private: - struct node - { - std::shared_ptr data; - std::unique_ptr next; - }; +class queue { +private: + struct node { + std::shared_ptr data; + std::unique_ptr next; + }; - std::mutex head_mutex; - std::unique_ptr head; - std::mutex tail_mutex; - node *tail; - std::condition_variable data_cond; + std::mutex head_mutex; + std::unique_ptr head; + std::mutex tail_mutex; + node* tail; + std::condition_variable data_cond; - node *get_tail() - { - std::lock_guard tail_lock(tail_mutex); - return tail; + node* get_tail() + { + std::lock_guard tail_lock(tail_mutex); + return tail; + } + + std::unique_ptr pop_head() + { + std::unique_ptr old_head = std::move(head); + head = std::move(old_head->next); + return old_head; + } + + std::unique_ptr try_pop_head() + { + std::lock_guard head_lock(head_mutex); + if (head.get() == get_tail()) { + return std::unique_ptr(); } + return pop_head(); + } - std::unique_ptr pop_head() - { - std::unique_ptr old_head = std::move(head); - head = std::move(old_head->next); - return old_head; + std::unique_ptr try_pop_head(T& value) + { + std::lock_guard head_lock(head_mutex); + if (head.get() == get_tail()) { + return std::unique_ptr(); } + value = std::move(*head->data); + return pop_head(); + } - std::unique_ptr try_pop_head() + std::unique_lock wait_for_data() + { + std::unique_lock head_lock(head_mutex); + data_cond.wait(head_lock, [&] { return head.get() != queue::get_tail(); }); + return std::move(head_lock); + } + + std::unique_ptr wait_pop_head() + { + std::unique_lock head_lock(wait_for_data()); + return pop_head(); + } + + std::unique_ptr wait_pop_head(T& value) + { + std::unique_lock head_lock(wait_for_data()); + value = std::move(*head->data); + return pop_head(); + } + +public: + queue() : head(new node), tail(head.get()) {} + + queue(const queue& other) = delete; + queue& operator=(const queue& other) = delete; + + std::shared_ptr try_pop() + { + std::unique_ptr old_head = try_pop_head(); + return old_head ? old_head->data : std::shared_ptr(); + } + + bool try_pop(T& value) + { + std::unique_ptr const old_head = try_pop_head(value); + return old_head; + } + + std::shared_ptr wait_and_pop() + { + std::unique_ptr const old_head = wait_pop_head(); + return old_head->data; + } + + void wait_and_pop(T& value) + { + std::unique_ptr const old_head = wait_pop_value(value); + } + + void push(T new_value) + { + std::shared_ptr new_data(std::make_shared(std::move(new_value))); + std::unique_ptr p(new node); { - std::lock_guard head_lock(head_mutex); - if (head.get() == get_tail()) { - return std::unique_ptr(); - } - return pop_head(); + std::lock_guard tail_lock(tail_mutex); + tail->data = new_data; + node* const new_tail = p.get(); + tail->next = std::move(p); + tail = new_tail; } + data_cond.notify_one(); + } - std::unique_ptr try_pop_head(T& value) - { - std::lock_guard head_lock(head_mutex); - if (head.get() == get_tail()) { - return std::unique_ptr(); - } - value = std::move(*head->data); - return pop_head(); - } - - std::unique_lock wait_for_data() - { - std::unique_lock head_lock(head_mutex); - data_cond.wait(head_lock, [&]{return head.get() != queue::get_tail();}); - return std::move(head_lock); - } - - std::unique_ptr wait_pop_head() - { - std::unique_lock head_lock(wait_for_data()); - return pop_head(); - } - - std::unique_ptr wait_pop_head(T& value) - { - std::unique_lock head_lock(wait_for_data()); - value = std::move(*head->data); - return pop_head(); - } - - public: - queue():head(new node),tail(head.get()) - {} - - queue(const queue& other) = delete; - queue& operator=(const queue& other) = delete; - - std::shared_ptr try_pop() - { - std::unique_ptr old_head = try_pop_head(); - return old_head ? old_head->data : std::shared_ptr(); - } - - bool try_pop(T& value) - { - std::unique_ptr const old_head = try_pop_head(value); - return old_head; - } - - std::shared_ptr wait_and_pop() - { - std::unique_ptr const old_head = wait_pop_head(); - return old_head->data; - } - - void wait_and_pop(T& value) - { - std::unique_ptr const old_head = wait_pop_value(value); - } - - void push(T new_value) - { - std::shared_ptr new_data( - std::make_shared(std::move(new_value))); - std::unique_ptr p(new node); - { - std::lock_guard tail_lock(tail_mutex); - tail->data = new_data; - node *const new_tail = p.get(); - tail->next = std::move(p); - tail = new_tail; - } - data_cond.notify_one(); - } - - void empty() - { - std::lock_guard head_lock(head_mutex); - return (head.get(0 == get_tail())); - } + void empty() + { + std::lock_guard head_lock(head_mutex); + return (head.get(0 == get_tail())); + } }; - -void push(queue* q) +void +push(queue* q) { - for (int i = 0; i < 10; ++i) { - printf("pushing %d\n", i); - q->push(i); - } + for (int i = 0; i < 10; ++i) { + printf("pushing %d\n", i); + q->push(i); + } } -void pop(queue* q) +void +pop(queue* q) { - int i = 0; - for (int i = 0; i < 10; ++i) { - printf("poping %d\n", *q->wait_and_pop()); - } + int i = 0; + for (int i = 0; i < 10; ++i) { + printf("poping %d\n", *q->wait_and_pop()); + } } -int main() +int +main() { - queue q; - std::thread th1(push,&q); - std::thread th2(pop,&q); - th1.join(); - th2.join(); - return 0; + queue q; + std::thread th1(push, &q); + std::thread th2(pop, &q); + th1.join(); + th2.join(); + return 0; } - diff --git a/ch6/stack.cpp b/ch6/stack.cpp index e00feb1..ec8178e 100644 --- a/ch6/stack.cpp +++ b/ch6/stack.cpp @@ -1,62 +1,63 @@ #include #include -#include #include -#include #include +#include +#include template -class stack -{ - private: - std::stack data; - mutable std::mutex m; +class stack { +private: + std::stack data; + mutable std::mutex m; - public: - stack(){} +public: + stack() {} - stack(const stack& other) - { - std::lock_guard lock(other.m); - data = other.data; - } + stack(const stack& other) + { + std::lock_guard lock(other.m); + data = other.data; + } - stack& operator=(const stack&) = delete; + stack& operator=(const stack&) = delete; - void push(T new_value) - { - std::lock_guard lock(m); - data.push(new_value); - } + void push(T new_value) + { + std::lock_guard lock(m); + data.push(new_value); + } - std::shared_ptr pop() - { - std::lock_guard lock(m); - if (data.empty()) throw std::underflow_error("empty stack"); - std::shared_ptr const res(new T(data.top())); - data.pop(); - return res; - } + std::shared_ptr pop() + { + std::lock_guard lock(m); + if (data.empty()) + throw std::underflow_error("empty stack"); + std::shared_ptr const res(new T(data.top())); + data.pop(); + return res; + } - void pop(T& value) - { - std::lock_guard lock(m); - if (data.empty()) throw std::underflow_error("empty stack"); - value = data.top(); - data.pop(); - } + void pop(T& value) + { + std::lock_guard lock(m); + if (data.empty()) + throw std::underflow_error("empty stack"); + value = data.top(); + data.pop(); + } - bool empty() const - { - std::lock_guard lock(m); - return data.empty(); - } + bool empty() const + { + std::lock_guard lock(m); + return data.empty(); + } }; -int main() +int +main() { - stack s; - s.push(1); - std::cout << *s.pop() << std::endl; + stack s; + s.push(1); + std::cout << *s.pop() << std::endl; } - diff --git a/ch7/hazard_pointer.h b/ch7/hazard_pointer.h index 19c8f69..4e8f6eb 100644 --- a/ch7/hazard_pointer.h +++ b/ch7/hazard_pointer.h @@ -1,63 +1,53 @@ +#include #include #include -#include unsigned const max_hazard_pointers = 100; -struct hazard_pointer -{ - std::atomic id; - std::atomic pointer; +struct hazard_pointer { + std::atomic id; + std::atomic pointer; }; hazard_pointer hazard_pointers[max_hazard_pointers]; -class hp_owner -{ - hazard_pointer* hp; +class hp_owner { + hazard_pointer* hp; - public: - hp_owner(hp_owner const&)=delete; - hp_owner operator=(hp_owner const&)=delete; - hp_owner() - : hp(nullptr) - { - for (unsigned i = 0; i < max_hazard_pointers; ++i) { - std::thread::id old_id; - // try to claim ownership of a hazard pointer - if (hazard_pointers[i].id.compare_exchange_strong( - old_id, std::this_thread::get_id())) { - // successfully claimed the entry for the current thread, - // store it and stop the search - hp = &hazard_pointers[i]; - printf("hp: %ld\n", hp); - break; - } - // another threads owns this entry, move on to the next - } - // if you get to the end of the list without finding a free entry, - // there are too many threads using hazard pointers, so throw an - // exception - if (!hp) { - throw std::runtime_error("No hazard pointers available"); - } +public: + hp_owner(hp_owner const&) = delete; + hp_owner operator=(hp_owner const&) = delete; + hp_owner() : hp(nullptr) + { + for (unsigned i = 0; i < max_hazard_pointers; ++i) { + std::thread::id old_id; + // try to claim ownership of a hazard pointer + if (hazard_pointers[i].id.compare_exchange_strong( + old_id, std::this_thread::get_id())) { + // successfully claimed the entry for the current thread, + // store it and stop the search + hp = &hazard_pointers[i]; + printf("hp: %ld\n", hp); + break; + } + // another threads owns this entry, move on to the next } + // if you get to the end of the list without finding a free entry, + // there are too many threads using hazard pointers, so throw an + // exception + if (!hp) { + throw std::runtime_error("No hazard pointers available"); + } + } - std::atomic& get_pointer() - { - return hp->pointer; - } + std::atomic& get_pointer() { return hp->pointer; } - ~hp_owner() - { - // when each thread exits, if an instance of hp_owner was created - // for the thread, then it's destryoed. The destructor then resets - // the actual pointer to nullptr before setting the owner ID to - // std::thread::id(), allowing another thread to reuse the entry later. - // TODO: this causes crash - //hp->pointer.store(nullptr); - //hp->id.store(std::thread::id()); - } + ~hp_owner() + { + // when each thread exits, if an instance of hp_owner was created + // for the thread, then it's destryoed. The destructor then resets + // the actual pointer to nullptr before setting the owner ID to + // std::thread::id(), allowing another thread to reuse the entry later. + // TODO: this causes crash + // hp->pointer.store(nullptr); + // hp->id.store(std::thread::id()); + } }; - - - - diff --git a/ch7/queue_mpmc.cpp b/ch7/queue_mpmc.cpp index a8fe100..c7c6866 100644 --- a/ch7/queue_mpmc.cpp +++ b/ch7/queue_mpmc.cpp @@ -1,6 +1,6 @@ -#include -#include #include +#include +#include #include #include @@ -9,232 +9,210 @@ // mpmc queue template -class queue -{ - private: - struct node; - struct counted_node_ptr +class queue { +private: + struct node; + struct counted_node_ptr { + int external_count; + node* ptr; + }; + + std::atomic head; + std::atomic tail; + + struct node_counter { + unsigned internal_count : 30; + unsigned external_counters : 2; + // you need only 2 bits because there are at most two such + // counters (next and tail) + }; + + struct node { + std::atomic data; + std::atomic count; + std::atomic next; + + node() { - int external_count; - node* ptr; - }; + node_counter new_count; + new_count.internal_count = 0; + new_count.external_counters = 2; + // because every node starts out referenced from tail and + // from the next pointer of the previous node once you've + // actually aadded it to the queue + count.store(new_count); - std::atomic head; - std::atomic tail; - - struct node_counter - { - unsigned internal_count:30; - unsigned external_counters:2; - // you need only 2 bits because there are at most two such - // counters (next and tail) - }; - - struct node - { - std::atomic data; - std::atomic count; - std::atomic next; - - node() - { - node_counter new_count; - new_count.internal_count = 0; - new_count.external_counters = 2; - // because every node starts out referenced from tail and - // from the next pointer of the previous node once you've - // actually aadded it to the queue - count.store(new_count); - - counted_node_ptr new_next; - new_next.ptr = nullptr; - new_next.external_count = 0; - next.store(new_next); - } - - void release_ref() - { - node_counter old_counter= - count.load(std::memory_order_relaxed); - node_counter new_counter; - do - { - new_counter=old_counter; - --new_counter.internal_count; - } - while(!count.compare_exchange_strong( - old_counter,new_counter, - std::memory_order_acquire,std::memory_order_relaxed)); - if(!new_counter.internal_count && - !new_counter.external_counters) - { - delete this; - } - } - - }; - - void set_new_tail(counted_node_ptr &old_tail, - counted_node_ptr const &new_tail) - { - node* const current_tail_ptr = old_tail.ptr; - while(!tail.compare_exchange_weak(old_tail,new_tail) && - old_tail.ptr == current_tail_ptr); - if(old_tail.ptr == current_tail_ptr) - free_external_counter(old_tail); - else - current_tail_ptr->release_ref(); + counted_node_ptr new_next; + new_next.ptr = nullptr; + new_next.external_count = 0; + next.store(new_next); } - static void increase_external_count( - std::atomic& counter, - counted_node_ptr& old_counter) + void release_ref() { - counted_node_ptr new_counter; - do - { - new_counter = old_counter; - ++new_counter.external_count; - } - while(!counter.compare_exchange_strong( - old_counter,new_counter, - std::memory_order_acquire,std::memory_order_relaxed)); - old_counter.external_count = new_counter.external_count; + node_counter old_counter = count.load(std::memory_order_relaxed); + node_counter new_counter; + do { + new_counter = old_counter; + --new_counter.internal_count; + } while (!count.compare_exchange_strong(old_counter, + new_counter, + std::memory_order_acquire, + std::memory_order_relaxed)); + if (!new_counter.internal_count && !new_counter.external_counters) { + delete this; + } } + }; - static void free_external_counter(counted_node_ptr &old_node_ptr) - { - node* const ptr = old_node_ptr.ptr; - int const count_increase = old_node_ptr.external_count-2; - node_counter old_counter = - ptr->count.load(std::memory_order_relaxed); - node_counter new_counter; - do - { - new_counter=old_counter; - --new_counter.external_counters; - new_counter.internal_count+=count_increase; - } - while(!ptr->count.compare_exchange_strong( - old_counter,new_counter, - std::memory_order_acquire,std::memory_order_relaxed)); - if(!new_counter.internal_count && - !new_counter.external_counters) - { - delete ptr; - } + void set_new_tail(counted_node_ptr& old_tail, + counted_node_ptr const& new_tail) + { + node* const current_tail_ptr = old_tail.ptr; + while (!tail.compare_exchange_weak(old_tail, new_tail) && + old_tail.ptr == current_tail_ptr) + ; + if (old_tail.ptr == current_tail_ptr) + free_external_counter(old_tail); + else + current_tail_ptr->release_ref(); + } + + static void increase_external_count(std::atomic& counter, + counted_node_ptr& old_counter) + { + counted_node_ptr new_counter; + do { + new_counter = old_counter; + ++new_counter.external_count; + } while (!counter.compare_exchange_strong(old_counter, + new_counter, + std::memory_order_acquire, + std::memory_order_relaxed)); + old_counter.external_count = new_counter.external_count; + } + + static void free_external_counter(counted_node_ptr& old_node_ptr) + { + node* const ptr = old_node_ptr.ptr; + int const count_increase = old_node_ptr.external_count - 2; + node_counter old_counter = ptr->count.load(std::memory_order_relaxed); + node_counter new_counter; + do { + new_counter = old_counter; + --new_counter.external_counters; + new_counter.internal_count += count_increase; + } while (!ptr->count.compare_exchange_strong(old_counter, + new_counter, + std::memory_order_acquire, + std::memory_order_relaxed)); + if (!new_counter.internal_count && !new_counter.external_counters) { + delete ptr; } + } - public: - queue() - : head() - , tail() - {} +public: + queue() : head(), tail() {} - queue(const queue& other)=delete; - queue& operator=(const queue& other)=delete; + queue(const queue& other) = delete; + queue& operator=(const queue& other) = delete; - ~queue() - { - /* - while (node* const old_head = head.load()) { - head.store(old_head->next); - delete old_head; - } - */ + ~queue() + { + /* + while (node* const old_head = head.load()) { + head.store(old_head->next); + delete old_head; } + */ + } - void push(T new_value) - { - std::unique_ptr new_data(new T(new_value)); - counted_node_ptr new_next; - new_next.ptr = new node; - new_next.external_count=1; - counted_node_ptr old_tail=tail.load(); - for(;;) - { - increase_external_count(tail,old_tail); - T* old_data=nullptr; - if(old_tail.ptr->data.compare_exchange_strong( - old_data,new_data.get())) - { - counted_node_ptr old_next={0}; - if(!old_tail.ptr->next.compare_exchange_strong( - old_next,new_next)) - { - delete new_next.ptr; - new_next=old_next; - } - set_new_tail(old_tail, new_next); - new_data.release(); - break; - } - else - { - counted_node_ptr old_next={0}; - if(old_tail.ptr->next.compare_exchange_strong( - old_next,new_next)) - { - old_next=new_next; - new_next.ptr=new node; - } - set_new_tail(old_tail, old_next); - } + void push(T new_value) + { + std::unique_ptr new_data(new T(new_value)); + counted_node_ptr new_next; + new_next.ptr = new node; + new_next.external_count = 1; + counted_node_ptr old_tail = tail.load(); + for (;;) { + increase_external_count(tail, old_tail); + T* old_data = nullptr; + if (old_tail.ptr->data.compare_exchange_strong(old_data, + new_data.get())) { + counted_node_ptr old_next = {0}; + if (!old_tail.ptr->next.compare_exchange_strong(old_next, new_next)) { + delete new_next.ptr; + new_next = old_next; } - } - - std::unique_ptr pop() { - counted_node_ptr old_head = head.load(std::memory_order_relaxed); - - for(;;) { - increase_external_count(head, old_head); - - node* const ptr = old_head.ptr; - if (ptr==tail.load().ptr) { - ptr->release_ref(); - return std::unique_ptr(); - } - - counted_node_ptr next = ptr->next.load(); - - if (head.compare_exchange_strong(old_head, next)) { - T* const res=ptr->data.exchange(nullptr); - free_external_counter(old_head); - return std::unique_ptr(res); - } - ptr->release_ref(); + set_new_tail(old_tail, new_next); + new_data.release(); + break; + } + else { + counted_node_ptr old_next = {0}; + if (old_tail.ptr->next.compare_exchange_strong(old_next, new_next)) { + old_next = new_next; + new_next.ptr = new node; } + set_new_tail(old_tail, old_next); + } } + } + + std::unique_ptr pop() + { + counted_node_ptr old_head = head.load(std::memory_order_relaxed); + + for (;;) { + increase_external_count(head, old_head); + + node* const ptr = old_head.ptr; + if (ptr == tail.load().ptr) { + ptr->release_ref(); + return std::unique_ptr(); + } + + counted_node_ptr next = ptr->next.load(); + + if (head.compare_exchange_strong(old_head, next)) { + T* const res = ptr->data.exchange(nullptr); + free_external_counter(old_head); + return std::unique_ptr(res); + } + ptr->release_ref(); + } + } }; -void push(queue* q) +void +push(queue* q) { - for (int i = 0; i < 10; ++i) { - printf("pushing %d\n", i); - q->push(i); + for (int i = 0; i < 10; ++i) { + printf("pushing %d\n", i); + q->push(i); + } +} + +void +pop(queue* q) +{ + int i = 0; + while (i < 10) { + std::shared_ptr p = q->pop(); + if (p) { + printf("poping %d\n", *p); + ++i; } + } } -void pop(queue* q) +int +main() { - int i = 0; - while (i < 10) { - std::shared_ptr p = q->pop(); - if (p) { - printf("poping %d\n", *p); - ++i; - } - } + queue q; + std::thread t1(push, &q); + std::thread t2(pop, &q); + t1.join(); + t2.join(); + return 0; } - -int main() -{ - queue q; - std::thread t1(push, &q); - std::thread t2(pop, &q); - t1.join(); - t2.join(); - return 0; -} - - diff --git a/ch7/queue_spsc.cpp b/ch7/queue_spsc.cpp index f05c985..e48189a 100644 --- a/ch7/queue_spsc.cpp +++ b/ch7/queue_spsc.cpp @@ -1,102 +1,98 @@ -#include -#include #include +#include +#include #include #include template -class queue -{ - private: - struct node - { - std::shared_ptr data; - node* next; +class queue { +private: + struct node { + std::shared_ptr data; + node* next; - node() - : next(nullptr) - {} - }; + node() : next(nullptr) {} + }; - std::atomic head; - std::atomic tail; - - node* pop_head() - { - node* const old_head = head.load(); - if (old_head == tail.load()) { - return nullptr; - } - head.store(old_head->next); - return old_head; + std::atomic head; + std::atomic tail; + + node* pop_head() + { + node* const old_head = head.load(); + if (old_head == tail.load()) { + return nullptr; } - public: - queue() - : head(new node) - , tail(head.load()) - {} + head.store(old_head->next); + return old_head; + } - queue(const queue& other)=delete; - queue& operator=(const queue& other)=delete; +public: + queue() : head(new node), tail(head.load()) {} - ~queue() - { - while (node* const old_head = head.load()) { - head.store(old_head->next); - delete old_head; - } + queue(const queue& other) = delete; + queue& operator=(const queue& other) = delete; + + ~queue() + { + while (node* const old_head = head.load()) { + head.store(old_head->next); + delete old_head; + } + } + + std::shared_ptr pop() + { + node* old_head = pop_head(); + if (!old_head) { + return std::shared_ptr(); } - std::shared_ptr pop() - { - node* old_head = pop_head(); - if (!old_head) { - return std::shared_ptr(); - } + std::shared_ptr const res(old_head->data); + delete old_head; + return res; + } - std::shared_ptr const res(old_head->data); - delete old_head; - return res; - } - - void push(T new_value) - { - std::shared_ptr new_data(std::make_shared(new_value)); - node* p = new node; - node* const old_tail = tail.load(); - old_tail->data.swap(new_data); - old_tail->next = p; - tail.store(p); - } + void push(T new_value) + { + std::shared_ptr new_data(std::make_shared(new_value)); + node* p = new node; + node* const old_tail = tail.load(); + old_tail->data.swap(new_data); + old_tail->next = p; + tail.store(p); + } }; -void push(queue* q) +void +push(queue* q) { - for (int i = 0; i < 10; ++i) { - printf("pushing %d\n", i); - q->push(i); + for (int i = 0; i < 10; ++i) { + printf("pushing %d\n", i); + q->push(i); + } +} + +void +pop(queue* q) +{ + int i = 0; + while (i < 10) { + std::shared_ptr p = q->pop(); + if (p) { + printf("poping %d\n", *p); + ++i; } + } } -void pop(queue* q) +int +main() { - int i = 0; - while (i < 10) { - std::shared_ptr p = q->pop(); - if (p) { - printf("poping %d\n", *p); - ++i; - } - } + queue q; + std::thread t1(push, &q); + std::thread t2(pop, &q); + t1.join(); + t2.join(); + return 0; } - -int main() -{ - queue q; - std::thread t1(push, &q); - std::thread t2(pop, &q); - t1.join(); - t2.join(); - return 0; -} - diff --git a/ch7/stack.cpp b/ch7/stack.cpp index 21fbc8f..3fd9cd4 100644 --- a/ch7/stack.cpp +++ b/ch7/stack.cpp @@ -7,168 +7,161 @@ // to_be_deleted list would grow without bounds, and you'd be essentailly // leaking memory again. If there aren't going to be any quiescent periods, // you need to find an alternative mechanism for reclaming the nodes. The key -// is to identify when no more threads are accesing a particular node so that +// is to identify when no more threads are accesing a particular node so that // it can reclaimed. By far the easiest such mechanism to reason about is the // use of hazard ponters. -#include -#include #include +#include +#include #include #include template -class stack -{ - private: - struct node - { - std::shared_ptr data; - node *next; +class stack { +private: + struct node { + std::shared_ptr data; + node* next; - node(const T& data_) - : data(std::make_shared(data_)) - {} - }; + node(const T& data_) : data(std::make_shared(data_)) {} + }; - std::atomic head; - std::atomic threads_in_pop; - std::atomic to_be_deleted; + std::atomic head; + std::atomic threads_in_pop; + std::atomic to_be_deleted; - - static void delete_nodes(node *nodes) - { - while (nodes) { - node *next = nodes->next; - delete nodes; - nodes = next; - } + static void delete_nodes(node* nodes) + { + while (nodes) { + node* next = nodes->next; + delete nodes; + nodes = next; } + } - void try_reclaim(node* old_head) - { - if (threads_in_pop == 1) { - // claim list of to-be-deleted nodes - node* nodes_to_delete = to_be_deleted.exchange(nullptr); + void try_reclaim(node* old_head) + { + if (threads_in_pop == 1) { + // claim list of to-be-deleted nodes + node* nodes_to_delete = to_be_deleted.exchange(nullptr); - // are you the only thread in pop()? - if (!--threads_in_pop) { - // on other thread can be accessing this list of pending nodes. - // There may be new pending nodes, but you're not bothered - // about them for now, as long as it's safe to reclaim your - // list. - delete_nodes(nodes_to_delete); - } - else if (nodes_to_delete) { - // not safe to reclaim the nodes, so if there are any, - // you must chain them back onto the list of nodes - // pending deletion. - // This can happen if there are multiple threads accessing the - // data structure concurrently. Other threads might have - // called pop() in between the first tet of thread_in_pop and - // the "claiming" of the list, potentially adding new nodes to - // the list that are still being accesed by one or more of - // those other threads. - chain_pending_nodes(nodes_to_delete); - } - delete old_head; - } - else { - // not safe to delete any nodes, add the node to the pending list - chain_pending_node(old_head); - --threads_in_pop; - } + // are you the only thread in pop()? + if (!--threads_in_pop) { + // on other thread can be accessing this list of pending nodes. + // There may be new pending nodes, but you're not bothered + // about them for now, as long as it's safe to reclaim your + // list. + delete_nodes(nodes_to_delete); + } + else if (nodes_to_delete) { + // not safe to reclaim the nodes, so if there are any, + // you must chain them back onto the list of nodes + // pending deletion. + // This can happen if there are multiple threads accessing the + // data structure concurrently. Other threads might have + // called pop() in between the first tet of thread_in_pop and + // the "claiming" of the list, potentially adding new nodes to + // the list that are still being accesed by one or more of + // those other threads. + chain_pending_nodes(nodes_to_delete); + } + delete old_head; } - - void chain_pending_nodes(node* nodes) - { - node* last = nodes; - // traverse the chain to find the end - while (node* const next = last->next) { - last = next; - } - chain_pending_nodes(nodes, last); + else { + // not safe to delete any nodes, add the node to the pending list + chain_pending_node(old_head); + --threads_in_pop; } + } - void chain_pending_nodes(node* first, node* last) - { - // replace the next pointer from the last node with - // the current to_be_deleted pointer - last->next = to_be_deleted; - // store the first node in the chain as the new to_be_deleted pointer - // have to use compare_exchange_weak in a loop here in order to ensure - // that you don't leak any nodes that have been added by another thread - while (!to_be_deleted.compare_exchange_weak( - last->next,first)); - + void chain_pending_nodes(node* nodes) + { + node* last = nodes; + // traverse the chain to find the end + while (node* const next = last->next) { + last = next; } + chain_pending_nodes(nodes, last); + } - void chain_pending_node(node* n) - { - // adding a single node onto the list is a special case where the - // first node onto the list is a special case where the first node - // in the chain to be added is the same as the last one. - chain_pending_nodes(n,n); - } - - public: - stack() - : head(nullptr) - , threads_in_pop(0) - , to_be_deleted(nullptr) - {} - - void push(const T& data) - { - node *const new_node = new node(data); - new_node->next = head.load(); - // loop to gurantee that last->next is correct - while (!head.compare_exchange_weak(new_node->next, new_node)); - } - - std::shared_ptr pop() - { - ++threads_in_pop; // increase counter before doing anything else - node *old_head = head.load(); - while (old_head && - !head.compare_exchange_weak(old_head, old_head->next)); - std::shared_ptr res; - if (old_head) { - res.swap(old_head->data); // extract data from node rather than - // coping pointer - } - try_reclaim(old_head); // reclaim deleted nodes if you can - return res; + void chain_pending_nodes(node* first, node* last) + { + // replace the next pointer from the last node with + // the current to_be_deleted pointer + last->next = to_be_deleted; + // store the first node in the chain as the new to_be_deleted pointer + // have to use compare_exchange_weak in a loop here in order to ensure + // that you don't leak any nodes that have been added by another thread + while (!to_be_deleted.compare_exchange_weak(last->next, first)) + ; + } + + void chain_pending_node(node* n) + { + // adding a single node onto the list is a special case where the + // first node onto the list is a special case where the first node + // in the chain to be added is the same as the last one. + chain_pending_nodes(n, n); + } + +public: + stack() : head(nullptr), threads_in_pop(0), to_be_deleted(nullptr) {} + + void push(const T& data) + { + node* const new_node = new node(data); + new_node->next = head.load(); + // loop to gurantee that last->next is correct + while (!head.compare_exchange_weak(new_node->next, new_node)) + ; + } + + std::shared_ptr pop() + { + ++threads_in_pop; // increase counter before doing anything else + node* old_head = head.load(); + while (old_head && !head.compare_exchange_weak(old_head, old_head->next)) + ; + std::shared_ptr res; + if (old_head) { + res.swap(old_head->data); // extract data from node rather than + // coping pointer } + try_reclaim(old_head); // reclaim deleted nodes if you can + return res; + } }; -void push(stack* s) +void +push(stack* s) { - for (int i = 0; i < 10; ++i) { - printf("pushing %d\n", i); - s->push(i); + for (int i = 0; i < 10; ++i) { + printf("pushing %d\n", i); + s->push(i); + } +} + +void +pop(stack* s) +{ + int count = 0; + std::shared_ptr e; + while (count < 10) { + if (e = s->pop()) { + printf("popping %d\n", *e); + ++count; } + } } -void pop(stack* s) +int +main() { - int count = 0; - std::shared_ptr e; - while (count < 10) { - if (e = s->pop()) { - printf("popping %d\n", *e); - ++count; - } - } + stack s; + std::thread t1(push, &s); + std::thread t2(pop, &s); + t1.join(); + t2.join(); + return 0; } - -int main() -{ - stack s; - std::thread t1(push, &s); - std::thread t2(pop, &s); - t1.join(); - t2.join(); - return 0; -} - diff --git a/ch7/stack_hp.cpp b/ch7/stack_hp.cpp index f25c4d1..28abdb3 100644 --- a/ch7/stack_hp.cpp +++ b/ch7/stack_hp.cpp @@ -1,193 +1,191 @@ -#include -#include #include +#include +#include #include #include #include "hazard_pointer.h" -std::atomic& get_hazard_pointer_for_current_thread() +std::atomic& +get_hazard_pointer_for_current_thread() { - // The first time each thread calls this function, a new instance of - // hp_owner is created. The constructor for this new instance then - // searchs through the table of owner/pointer pairs looking for an entry - // without an owner. It uses compare_exchange_strong() to check for an - // entry without an owner and claim it in one go. - // - // Once the hp_owner instance has been created for a given thread, further - // accesses are much faster because the pointer is cached, so the table - // doesn't have to be scanned again. - - printf("get harzard pointer for current thread, thread id: %d\n", std::this_thread::get_id()); - thread_local static hp_owner hazard; - return hazard.get_pointer(); + // The first time each thread calls this function, a new instance of + // hp_owner is created. The constructor for this new instance then + // searchs through the table of owner/pointer pairs looking for an entry + // without an owner. It uses compare_exchange_strong() to check for an + // entry without an owner and claim it in one go. + // + // Once the hp_owner instance has been created for a given thread, further + // accesses are much faster because the pointer is cached, so the table + // doesn't have to be scanned again. + + printf("get harzard pointer for current thread, thread id: %d\n", + std::this_thread::get_id()); + thread_local static hp_owner hazard; + return hazard.get_pointer(); } -bool outstanding_hazard_pointers_for(void *p) +bool +outstanding_hazard_pointers_for(void* p) { - for (unsigned i = 0; i < max_hazard_pointers; ++i) { - if (hazard_pointers[i].pointer.load() == p) { - return true; - } + for (unsigned i = 0; i < max_hazard_pointers; ++i) { + if (hazard_pointers[i].pointer.load() == p) { + return true; } - return false; + } + return false; } template -void do_delete(void* p) +void +do_delete(void* p) { - delete static_cast(p); + delete static_cast(p); } -struct data_to_reclaim -{ - void* data; - std::function deleter; - data_to_reclaim* next; +struct data_to_reclaim { + void* data; + std::function deleter; + data_to_reclaim* next; - template - data_to_reclaim(T* p) - : data(p) - , deleter(&do_delete) - , next(0) - {} + template + data_to_reclaim(T* p) : data(p), deleter(&do_delete), next(0) + { + } - ~data_to_reclaim() - { - deleter(data); - } + ~data_to_reclaim() { deleter(data); } }; std::atomic nodes_to_reclaim; -void add_to_reclaim_list(data_to_reclaim* node) +void +add_to_reclaim_list(data_to_reclaim* node) { - node->next = nodes_to_reclaim.load(); - while (!nodes_to_reclaim.compare_exchange_weak(node->next, node)); -} - -template -void reclaim_later(T* data) -{ - add_to_reclaim_list(new data_to_reclaim(data)); -} - -void delete_nodes_with_no_hazards() -{ - // first claims the entire list of nodes to be reclaimed; - // ensures that this is the only thread trying to reclaim - // this particular set of nodes; other threads are now free - // to add futher nodes to the list or event try to reclaim - // them without impacting the operation of this thread. - data_to_reclaim* current = nodes_to_reclaim.exchange(nullptr); - - while (current) { - data_to_reclaim* const next = current->next; - - // check each node in turn to see if there are any outstanding - // hazard pointers. - if (!outstanding_hazard_pointers_for(current->data)) { - // if there aren't, delete the entry - delete current; - } - else { - // otherwise, just add the item back on the list for - // reclaiming later - add_to_reclaim_list(current); - } - current=next; - } + node->next = nodes_to_reclaim.load(); + while (!nodes_to_reclaim.compare_exchange_weak(node->next, node)) + ; } template -class stack +void +reclaim_later(T* data) { - private: - struct node - { - std::shared_ptr data; - node *next; + add_to_reclaim_list(new data_to_reclaim(data)); +} - node(const T& data_) - : data(std::make_shared(data_)) - {} - }; +void +delete_nodes_with_no_hazards() +{ + // first claims the entire list of nodes to be reclaimed; + // ensures that this is the only thread trying to reclaim + // this particular set of nodes; other threads are now free + // to add futher nodes to the list or event try to reclaim + // them without impacting the operation of this thread. + data_to_reclaim* current = nodes_to_reclaim.exchange(nullptr); - std::atomic head; + while (current) { + data_to_reclaim* const next = current->next; - public: - stack() - : head(nullptr) - {} - - void push(const T& data) - { - node *const new_node = new node(data); - new_node->next = head.load(); - while (!head.compare_exchange_weak(new_node->next, new_node)); + // check each node in turn to see if there are any outstanding + // hazard pointers. + if (!outstanding_hazard_pointers_for(current->data)) { + // if there aren't, delete the entry + delete current; } - - std::shared_ptr pop() - { - std::atomic& hp = get_hazard_pointer_for_current_thread(); - node* old_head = head.load(); - do { - node* temp; - do { // loop until you've set the harzard pointer to head - temp = old_head; - hp.store(old_head); - old_head = head.load(); - } while (old_head != temp); - } - while (old_head && - !head.compare_exchange_strong(old_head, old_head->next)); - hp.store(nullptr); // clear hazard pointer once you're finished - std::shared_ptr res; - if (old_head) { - res.swap(old_head->data); - if (outstanding_hazard_pointers_for(old_head)) { - // check for hazard pointers referencing - // a node before you delete it - reclaim_later(old_head); - } - else { - delete old_head; - } - delete_nodes_with_no_hazards(); - } - return res; + else { + // otherwise, just add the item back on the list for + // reclaiming later + add_to_reclaim_list(current); } + current = next; + } +} + +template +class stack { +private: + struct node { + std::shared_ptr data; + node* next; + + node(const T& data_) : data(std::make_shared(data_)) {} + }; + + std::atomic head; + +public: + stack() : head(nullptr) {} + + void push(const T& data) + { + node* const new_node = new node(data); + new_node->next = head.load(); + while (!head.compare_exchange_weak(new_node->next, new_node)) + ; + } + + std::shared_ptr pop() + { + std::atomic& hp = get_hazard_pointer_for_current_thread(); + node* old_head = head.load(); + do { + node* temp; + do { // loop until you've set the harzard pointer to head + temp = old_head; + hp.store(old_head); + old_head = head.load(); + } while (old_head != temp); + } while (old_head && + !head.compare_exchange_strong(old_head, old_head->next)); + hp.store(nullptr); // clear hazard pointer once you're finished + std::shared_ptr res; + if (old_head) { + res.swap(old_head->data); + if (outstanding_hazard_pointers_for(old_head)) { + // check for hazard pointers referencing + // a node before you delete it + reclaim_later(old_head); + } + else { + delete old_head; + } + delete_nodes_with_no_hazards(); + } + return res; + } }; -void push(stack* s) +void +push(stack* s) { - printf("starting push\n"); - for (int i = 0; i < 10; ++i) { - printf("pushing %d\n", i); - s->push(i); + printf("starting push\n"); + for (int i = 0; i < 10; ++i) { + printf("pushing %d\n", i); + s->push(i); + } +} + +void +pop(stack* s) +{ + printf("starting pop\n"); + int count = 0; + std::shared_ptr e; + while (count < 10) { + if (e = s->pop()) { + printf("popping %d\n", *e); + ++count; } + } } -void pop(stack* s) +int +main() { - printf("starting pop\n"); - int count = 0; - std::shared_ptr e; - while (count < 10) { - if (e = s->pop()) { - printf("popping %d\n", *e); - ++count; - } - } + printf("creating stack\n"); + stack s; + printf("stack created\n"); + std::thread t1(push, &s); + std::thread t2(pop, &s); + t1.join(); + t2.join(); + return 0; } - -int main() -{ - printf("creating stack\n"); - stack s; - printf("stack created\n"); - std::thread t1(push, &s); - std::thread t2(pop, &s); - t1.join(); - t2.join(); - return 0; -} - diff --git a/ch7/stack_ref.cpp b/ch7/stack_ref.cpp index 7d2c46d..9db7c63 100644 --- a/ch7/stack_ref.cpp +++ b/ch7/stack_ref.cpp @@ -1,183 +1,171 @@ -#include -#include #include +#include +#include #include #include template -class stack -{ - private: - struct node; - - // the external count is kept alongside the poiner to the node and is - // increased every time the pointer is read. When the reader is finished - // with the node, it decraes the internal count. A simple operation that - // reads the pointer will thus leave the external count increaesd by one - // and the internal count decreased by one when it's finished. - // - // When the external count/pointer pairing is no longer required (that is, - // the node is no longer accessbile from a location accessible to multple - // threads), the internal count is increased by the value of the external - // count minus one and external counter is discarded. Once the internal - // count is equal to zero, there are no outstanding references to the node - // and it can be safely deleted. - struct counted_node_ptr - { - int external_count; - node *ptr; - }; +class stack { +private: + struct node; - struct node - { - std::shared_ptr data; - std::atomic_int internal_count; - counted_node_ptr next; + // the external count is kept alongside the poiner to the node and is + // increased every time the pointer is read. When the reader is finished + // with the node, it decraes the internal count. A simple operation that + // reads the pointer will thus leave the external count increaesd by one + // and the internal count decreased by one when it's finished. + // + // When the external count/pointer pairing is no longer required (that is, + // the node is no longer accessbile from a location accessible to multple + // threads), the internal count is increased by the value of the external + // count minus one and external counter is discarded. Once the internal + // count is equal to zero, there are no outstanding references to the node + // and it can be safely deleted. + struct counted_node_ptr { + int external_count; + node* ptr; + }; - node(const T& data_) - : data(new T(data_)) - , internal_count(0) - {} - }; + struct node { + std::shared_ptr data; + std::atomic_int internal_count; + counted_node_ptr next; - std::atomic head; - // NOTE: on those platforms that support a double-word-compare-and-swap - // operation, counted_node_ptr will be small enough for - // std::atomic to be lock-free. If it isn't on your - // platform, you might be better off using the std::shared_ptr<> version, - // because std::atomic<> will use a mutex to guarantee atomicity when the - // type is too large for the pltaform's atomic instrcutions (thus rending - // your "lock-free" algorithm lock-based after all). Alternatively, if - // you are're willing to limit the size of the counter, and you know that - // your platform has spare bits in a pointer (for example, because the - // address space is only 48 bits but a pointer is 64 bits), you can store - // the count inside the spare bits of the pointer to fit it all back in a - // single machine word. + node(const T& data_) : data(new T(data_)), internal_count(0) {} + }; + std::atomic head; + // NOTE: on those platforms that support a double-word-compare-and-swap + // operation, counted_node_ptr will be small enough for + // std::atomic to be lock-free. If it isn't on your + // platform, you might be better off using the std::shared_ptr<> version, + // because std::atomic<> will use a mutex to guarantee atomicity when the + // type is too large for the pltaform's atomic instrcutions (thus rending + // your "lock-free" algorithm lock-based after all). Alternatively, if + // you are're willing to limit the size of the counter, and you know that + // your platform has spare bits in a pointer (for example, because the + // address space is only 48 bits but a pointer is 64 bits), you can store + // the count inside the spare bits of the pointer to fit it all back in a + // single machine word. - // once you've loaded the value of head, you must first increaes the count - // of external references to the head node to indicate that you're - // referencing it and to ensure that it's safe to deference it. - // By incrementing the external reference count, you ensure that the - // pointer remains valid for the duration of your access. - void increase_head_count(counted_node_ptr& old_counter) - { - counted_node_ptr new_counter; + // once you've loaded the value of head, you must first increaes the count + // of external references to the head node to indicate that you're + // referencing it and to ensure that it's safe to deference it. + // By incrementing the external reference count, you ensure that the + // pointer remains valid for the duration of your access. + void increase_head_count(counted_node_ptr& old_counter) + { + counted_node_ptr new_counter; - do - { - new_counter = old_counter; - ++new_counter.external_count; + do { + new_counter = old_counter; + ++new_counter.external_count; + } while (!head.compare_exchange_strong(old_counter, new_counter)); + + old_counter.external_count = new_counter.external_count; + } + +public: + ~stack() + { + while (pop()) + ; + } + + void push(const T& data) + { + counted_node_ptr new_node; + new_node.ptr = new node(data); + // internal_count is zeor, and the external_count is one; + // because this is a new node, there's currently only one + // external reference to the node (the head pointer itself). + new_node.external_count = 1; + new_node.ptr->next = head.load(); + while (!head.compare_exchange_weak(new_node.ptr->next, new_node)) + ; + } + + std::shared_ptr pop() + { + counted_node_ptr old_head = head.load(); + for (;;) { + increase_head_count(old_head); + node* ptr = old_head.ptr; + // if the pointer is a null pointer, you're at the end of list: + // no more entires + if (!ptr) { + return std::shared_ptr(); + } + + // if the pointer isn't a null pointer, try to remove the node + if (head.compare_exchange_strong(old_head, ptr->next)) { + // you've taken the ownership of the node and can swap out + // the data in prepration for returning it. + std::shared_ptr res; + res.swap(ptr->data); + + // you've removed the node from the list, so you drop one + // off the count for that, and you're no longer accessing + // the node from this thread, so you drop another off the + // count for that. + const int count_increase = old_head.external_count - 2; + + // if the reference count is now zero, the previous value + // (which is what fetch_add returns) was the negative of what + // you just added, in which case you can delete the node. + if (ptr->internal_count.fetch_add(count_increase) == -count_increase) { + delete ptr; } - while (!head.compare_exchange_strong(old_counter, new_counter)); - old_counter.external_count = new_counter.external_count; - } - - public: - ~stack() - { - while (pop()); - } - - void push(const T& data) - { - counted_node_ptr new_node; - new_node.ptr = new node(data); - // internal_count is zeor, and the external_count is one; - // because this is a new node, there's currently only one - // external reference to the node (the head pointer itself). - new_node.external_count = 1; - new_node.ptr->next = head.load(); - while (!head.compare_exchange_weak(new_node.ptr->next, new_node)); - } - - std::shared_ptr pop() - { - counted_node_ptr old_head = head.load(); - for (;;) - { - increase_head_count(old_head); - node* ptr = old_head.ptr; - // if the pointer is a null pointer, you're at the end of list: - // no more entires - if (!ptr) - { - return std::shared_ptr(); - } - - // if the pointer isn't a null pointer, try to remove the node - if (head.compare_exchange_strong(old_head,ptr->next)) - { - // you've taken the ownership of the node and can swap out - // the data in prepration for returning it. - std::shared_ptr res; - res.swap(ptr->data); - - // you've removed the node from the list, so you drop one - // off the count for that, and you're no longer accessing - // the node from this thread, so you drop another off the - // count for that. - const int count_increase = old_head.external_count - 2; - - // if the reference count is now zero, the previous value - // (which is what fetch_add returns) was the negative of what - // you just added, in which case you can delete the node. - if (ptr->internal_count.fetch_add(count_increase) == - -count_increase) - { - delete ptr; - } - - // whether or not you deleted the node, you've finished. - return res; - } - // if the compare/exchange fails, another therad removed your node - // before you did, or another thread added a new node to the stack. - // Either way, you need start again with the fresh value of head - // returned by the compare/exchange call. But first you must - // decrease the reference count on the node you were trying to - // remove. This thread won't access it anymore. If you're the last - // thread to hold a reference (because another thread removed it - // from the stack), the internal reference count will be 1, so - // subtracing 1 will set the count to zero. In this case, you can - // delete the node here before you loop. - else if (ptr->internal_count.fetch_add(-1) == 1) - { - delete ptr; - } - } + // whether or not you deleted the node, you've finished. + return res; + } + // if the compare/exchange fails, another therad removed your node + // before you did, or another thread added a new node to the stack. + // Either way, you need start again with the fresh value of head + // returned by the compare/exchange call. But first you must + // decrease the reference count on the node you were trying to + // remove. This thread won't access it anymore. If you're the last + // thread to hold a reference (because another thread removed it + // from the stack), the internal reference count will be 1, so + // subtracing 1 will set the count to zero. In this case, you can + // delete the node here before you loop. + else if (ptr->internal_count.fetch_add(-1) == 1) { + delete ptr; + } } + } }; -void push(stack* s) +void +push(stack* s) { - for (int i = 0; i < 10; ++i) { - printf("pushing %d\n", i); - s->push(i); + for (int i = 0; i < 10; ++i) { + printf("pushing %d\n", i); + s->push(i); + } +} + +void +pop(stack* s) +{ + int count = 0; + std::shared_ptr e; + while (count < 10) { + if (e = s->pop()) { + printf("popping %d\n", *e); + ++count; } + } } -void pop(stack* s) +int +main() { - int count = 0; - std::shared_ptr e; - while (count < 10) { - if (e = s->pop()) { - printf("popping %d\n", *e); - ++count; - } - } + stack s; + std::thread t1(push, &s); + std::thread t2(pop, &s); + t1.join(); + t2.join(); + return 0; } - -int main() -{ - stack s; - std::thread t1(push, &s); - std::thread t2(pop, &s); - t1.join(); - t2.join(); - return 0; -} - - diff --git a/ch7/stack_sp.cpp b/ch7/stack_sp.cpp index 10f3acc..dc5fb3b 100644 --- a/ch7/stack_sp.cpp +++ b/ch7/stack_sp.cpp @@ -1,70 +1,70 @@ -#include -#include #include #include +#include +#include template -class stack -{ - private: - struct node - { - std::shared_ptr data; - std::shared_ptr next; +class stack { +private: + struct node { + std::shared_ptr data; + std::shared_ptr next; - node(T const& data_) - : data(std::make_shared(data_)) - {} - }; + node(T const& data_) : data(std::make_shared(data_)) {} + }; - std::shared_ptr head; - public: - void push(T const& data) - { - std::shared_ptr const new_node = std::make_shared(data); - new_node->next = std::atomic_load(head); - while (!std::atomic_compare_exchange_weak(&head, - &new_node->next, new_node)); - } - std::shared_ptr pop() - { - std::shared_ptr old_head = std::atomic_load(head); - while (old_head && !std::atomic_compare_exchange_weak(&head, - &old_head, old_head->next)); - return old_head ? old_head->data : std::shared_ptr(); - } + std::shared_ptr head; + +public: + void push(T const& data) + { + std::shared_ptr const new_node = std::make_shared(data); + new_node->next = std::atomic_load(head); + while (!std::atomic_compare_exchange_weak(&head, &new_node->next, new_node)) + ; + } + std::shared_ptr pop() + { + std::shared_ptr old_head = std::atomic_load(head); + while (old_head && + !std::atomic_compare_exchange_weak(&head, &old_head, old_head->next)) + ; + return old_head ? old_head->data : std::shared_ptr(); + } }; -void push(stack* s) +void +push(stack* s) { - for (int i = 0; i < 10; ++i) { - printf("pushing %d\n", i); - s->push(i); + for (int i = 0; i < 10; ++i) { + printf("pushing %d\n", i); + s->push(i); + } +} + +void +pop(stack* s) +{ + int count = 0; + std::shared_ptr e; + while (count < 10) { + if (e = s->pop()) { + printf("popping %d\n", *e); + ++count; } + } } -void pop(stack* s) +int +main() { - int count = 0; - std::shared_ptr e; - while (count < 10) { - if (e = s->pop()) { - printf("popping %d\n", *e); - ++count; - } - } + std::shared_ptr sp = std::make_shared(1); + // printf("std::atomic_is_lock_free(std::shared_ptr): %d\n", + // std::atomic_is_lock_free(&sp)); + stack s; + std::thread t1(push, &s); + std::thread t2(pop, &s); + t1.join(); + t2.join(); + return 0; } - -int main() -{ - std::shared_ptr sp = std::make_shared(1); - //printf("std::atomic_is_lock_free(std::shared_ptr): %d\n", - // std::atomic_is_lock_free(&sp)); - stack s; - std::thread t1(push, &s); - std::thread t2(pop, &s); - t1.join(); - t2.join(); - return 0; -} - diff --git a/source/listing_1.1.cpp b/source/listing_1.1.cpp index 92170a8..b80e10e 100644 --- a/source/listing_1.1.cpp +++ b/source/listing_1.1.cpp @@ -1,13 +1,15 @@ #include #include -void hello() +void +hello() { - std::cout<<"Hello Concurrent World\n"; + std::cout << "Hello Concurrent World\n"; } -int main() +int +main() { - std::thread t(hello); - t.join(); + std::thread t(hello); + t.join(); } diff --git a/source/listing_10.1.cpp b/source/listing_10.1.cpp index 865b94b..c7c4caa 100644 --- a/source/listing_10.1.cpp +++ b/source/listing_10.1.cpp @@ -1,42 +1,35 @@ -void test_concurrent_push_and_pop_on_empty_queue() +void +test_concurrent_push_and_pop_on_empty_queue() { - threadsafe_queue q; + threadsafe_queue q; - std::promise go,push_ready,pop_ready; - std::shared_future ready(go.get_future()); + std::promise go, push_ready, pop_ready; + std::shared_future ready(go.get_future()); - std::future push_done; - std::future pop_done; + std::future push_done; + std::future pop_done; - try - { - push_done=std::async(std::launch::async, - [&q,ready,&push_ready]() - { - push_ready.set_value(); - ready.wait(); - q.push(42); - } - ); - pop_done=std::async(std::launch::async, - [&q,ready,&pop_ready]() - { - pop_ready.set_value(); - ready.wait(); - return q.pop(); - } - ); - push_ready.get_future().wait(); - pop_ready.get_future().wait(); - go.set_value(); + try { + push_done = std::async(std::launch::async, [&q, ready, &push_ready]() { + push_ready.set_value(); + ready.wait(); + q.push(42); + }); + pop_done = std::async(std::launch::async, [&q, ready, &pop_ready]() { + pop_ready.set_value(); + ready.wait(); + return q.pop(); + }); + push_ready.get_future().wait(); + pop_ready.get_future().wait(); + go.set_value(); - push_done.get(); - assert(pop_done.get()==42); - assert(q.empty()); - } - catch(...) - { - go.set_value(); - throw; - } + push_done.get(); + assert(pop_done.get() == 42); + assert(q.empty()); + } + catch (...) { + go.set_value(); + throw; + } } diff --git a/source/listing_2.1.cpp b/source/listing_2.1.cpp index 45d2193..ebdb95d 100644 --- a/source/listing_2.1.cpp +++ b/source/listing_2.1.cpp @@ -1,35 +1,35 @@ #include -void do_something(int& i) +void +do_something(int& i) { - ++i; + ++i; } -struct func -{ - int& i; +struct func { + int& i; - func(int& i_):i(i_){} + func(int& i_) : i(i_) {} - void operator()() - { - for(unsigned j=0;j<1000000;++j) - { - do_something(i); - } + void operator()() + { + for (unsigned j = 0; j < 1000000; ++j) { + do_something(i); } + } }; - -void oops() +void +oops() { - int some_local_state=0; - func my_func(some_local_state); - std::thread my_thread(my_func); - my_thread.detach(); + int some_local_state = 0; + func my_func(some_local_state); + std::thread my_thread(my_func); + my_thread.detach(); } -int main() +int +main() { - oops(); + oops(); } diff --git a/source/listing_2.2.cpp b/source/listing_2.2.cpp index c952752..fa8c9f2 100644 --- a/source/listing_2.2.cpp +++ b/source/listing_2.2.cpp @@ -1,46 +1,47 @@ #include -void do_something(int& i) +void +do_something(int& i) { - ++i; + ++i; } -struct func -{ - int& i; +struct func { + int& i; - func(int& i_):i(i_){} + func(int& i_) : i(i_) {} - void operator()() - { - for(unsigned j=0;j<1000000;++j) - { - do_something(i); - } + void operator()() + { + for (unsigned j = 0; j < 1000000; ++j) { + do_something(i); } + } }; -void do_something_in_current_thread() -{} - -void f() +void +do_something_in_current_thread() { - int some_local_state=0; - func my_func(some_local_state); - std::thread t(my_func); - try - { - do_something_in_current_thread(); - } - catch(...) - { - t.join(); - throw; - } +} + +void +f() +{ + int some_local_state = 0; + func my_func(some_local_state); + std::thread t(my_func); + try { + do_something_in_current_thread(); + } + catch (...) { t.join(); + throw; + } + t.join(); } -int main() +int +main() { - f(); + f(); } diff --git a/source/listing_2.3.cpp b/source/listing_2.3.cpp index 5c48223..cdc27c9 100644 --- a/source/listing_2.3.cpp +++ b/source/listing_2.3.cpp @@ -1,58 +1,57 @@ #include -class thread_guard -{ - std::thread& t; +class thread_guard { + std::thread& t; + public: - explicit thread_guard(std::thread& t_): - t(t_) - {} - ~thread_guard() - { - if(t.joinable()) - { - t.join(); - } + explicit thread_guard(std::thread& t_) : t(t_) {} + ~thread_guard() + { + if (t.joinable()) { + t.join(); } - thread_guard(thread_guard const&)=delete; - thread_guard& operator=(thread_guard const&)=delete; + } + thread_guard(thread_guard const&) = delete; + thread_guard& operator=(thread_guard const&) = delete; }; -void do_something(int& i) +void +do_something(int& i) { - ++i; + ++i; } -struct func -{ - int& i; +struct func { + int& i; - func(int& i_):i(i_){} + func(int& i_) : i(i_) {} - void operator()() - { - for(unsigned j=0;j<1000000;++j) - { - do_something(i); - } + void operator()() + { + for (unsigned j = 0; j < 1000000; ++j) { + do_something(i); } + } }; -void do_something_in_current_thread() -{} - - -void f() +void +do_something_in_current_thread() { - int some_local_state; - func my_func(some_local_state); - std::thread t(my_func); - thread_guard g(t); - - do_something_in_current_thread(); } -int main() +void +f() { - f(); + int some_local_state; + func my_func(some_local_state); + std::thread t(my_func); + thread_guard g(t); + + do_something_in_current_thread(); +} + +int +main() +{ + f(); } diff --git a/source/listing_2.4.cpp b/source/listing_2.4.cpp index 702afa7..9bab1c3 100644 --- a/source/listing_2.4.cpp +++ b/source/listing_2.4.cpp @@ -1,61 +1,61 @@ -#include #include +#include -void open_document_and_display_gui(std::string const& filename) -{} - -bool done_editing() +void +open_document_and_display_gui(std::string const& filename) { - return true; } -enum command_type{ - open_new_document +bool +done_editing() +{ + return true; +} + +enum command_type { open_new_document }; + +struct user_command { + command_type type; + + user_command() : type(open_new_document) {} }; - -struct user_command +user_command +get_user_input() { - command_type type; - - user_command(): - type(open_new_document) - {} -}; - -user_command get_user_input() -{ - return user_command(); + return user_command(); } -std::string get_filename_from_user() +std::string +get_filename_from_user() { - return "foo.doc"; + return "foo.doc"; } -void process_user_input(user_command const& cmd) -{} - -void edit_document(std::string const& filename) +void +process_user_input(user_command const& cmd) { - open_document_and_display_gui(filename); - while(!done_editing()) - { - user_command cmd=get_user_input(); - if(cmd.type==open_new_document) - { - std::string const new_name=get_filename_from_user(); - std::thread t(edit_document,new_name); - t.detach(); - } - else - { - process_user_input(cmd); - } +} + +void +edit_document(std::string const& filename) +{ + open_document_and_display_gui(filename); + while (!done_editing()) { + user_command cmd = get_user_input(); + if (cmd.type == open_new_document) { + std::string const new_name = get_filename_from_user(); + std::thread t(edit_document, new_name); + t.detach(); } + else { + process_user_input(cmd); + } + } } -int main() +int +main() { - edit_document("bar.doc"); + edit_document("bar.doc"); } diff --git a/source/listing_2.5.cpp b/source/listing_2.5.cpp index 5913bef..e1911c4 100644 --- a/source/listing_2.5.cpp +++ b/source/listing_2.5.cpp @@ -1,27 +1,34 @@ #include -void some_function() -{} - -void some_other_function(int) -{} - -std::thread f() +void +some_function() { - void some_function(); - return std::thread(some_function); -} -std::thread g() -{ - void some_other_function(int); - std::thread t(some_other_function,42); - return t; } -int main() +void +some_other_function(int) { - std::thread t1=f(); - t1.join(); - std::thread t2=g(); - t2.join(); +} + +std::thread +f() +{ + void some_function(); + return std::thread(some_function); +} +std::thread +g() +{ + void some_other_function(int); + std::thread t(some_other_function, 42); + return t; +} + +int +main() +{ + std::thread t1 = f(); + t1.join(); + std::thread t2 = g(); + t2.join(); } diff --git a/source/listing_2.6.cpp b/source/listing_2.6.cpp index f08fff6..4448cfd 100644 --- a/source/listing_2.6.cpp +++ b/source/listing_2.6.cpp @@ -1,56 +1,55 @@ #include #include -class scoped_thread -{ - std::thread t; +class scoped_thread { + std::thread t; + public: - explicit scoped_thread(std::thread t_): - t(std::move(t_)) - { - if(!t.joinable()) - throw std::logic_error("No thread"); - } - ~scoped_thread() - { - t.join(); - } - scoped_thread(scoped_thread const&)=delete; - scoped_thread& operator=(scoped_thread const&)=delete; + explicit scoped_thread(std::thread t_) : t(std::move(t_)) + { + if (!t.joinable()) + throw std::logic_error("No thread"); + } + ~scoped_thread() { t.join(); } + scoped_thread(scoped_thread const&) = delete; + scoped_thread& operator=(scoped_thread const&) = delete; }; -void do_something(int& i) +void +do_something(int& i) { - ++i; + ++i; } -struct func -{ - int& i; +struct func { + int& i; - func(int& i_):i(i_){} + func(int& i_) : i(i_) {} - void operator()() - { - for(unsigned j=0;j<1000000;++j) - { - do_something(i); - } + void operator()() + { + for (unsigned j = 0; j < 1000000; ++j) { + do_something(i); } + } }; -void do_something_in_current_thread() -{} - -void f() +void +do_something_in_current_thread() { - int some_local_state; - scoped_thread t(std::thread(func(some_local_state))); - - do_something_in_current_thread(); } -int main() +void +f() { - f(); + int some_local_state; + scoped_thread t(std::thread(func(some_local_state))); + + do_something_in_current_thread(); +} + +int +main() +{ + f(); } diff --git a/source/listing_2.7.cpp b/source/listing_2.7.cpp index 4aa81d2..05f4bc1 100644 --- a/source/listing_2.7.cpp +++ b/source/listing_2.7.cpp @@ -1,23 +1,26 @@ -#include -#include #include #include +#include +#include -void do_work(unsigned id) -{} - -void f() +void +do_work(unsigned id) { - std::vector threads; - for(unsigned i=0;i<20;++i) - { - threads.push_back(std::thread(do_work,i)); - } - std::for_each(threads.begin(),threads.end(), - std::mem_fn(&std::thread::join)); } -int main() +void +f() { - f(); + std::vector threads; + for (unsigned i = 0; i < 20; ++i) { + threads.push_back(std::thread(do_work, i)); + } + std::for_each( + threads.begin(), threads.end(), std::mem_fn(&std::thread::join)); +} + +int +main() +{ + f(); } diff --git a/source/listing_2.8.cpp b/source/listing_2.8.cpp index c2dc415..6852316 100644 --- a/source/listing_2.8.cpp +++ b/source/listing_2.8.cpp @@ -1,67 +1,66 @@ -#include -#include #include #include -#include #include +#include +#include +#include -template -struct accumulate_block -{ - void operator()(Iterator first,Iterator last,T& result) - { - result=std::accumulate(first,last,result); - } +template +struct accumulate_block { + void operator()(Iterator first, Iterator last, T& result) + { + result = std::accumulate(first, last, result); + } }; -template -T parallel_accumulate(Iterator first,Iterator last,T init) +template +T +parallel_accumulate(Iterator first, Iterator last, T init) { - unsigned long const length=std::distance(first,last); + unsigned long const length = std::distance(first, last); - if(!length) - return init; + if (!length) + return init; - unsigned long const min_per_thread=25; - unsigned long const max_threads= - (length+min_per_thread-1)/min_per_thread; + unsigned long const min_per_thread = 25; + unsigned long const max_threads = + (length + min_per_thread - 1) / min_per_thread; - unsigned long const hardware_threads= - std::thread::hardware_concurrency(); + unsigned long const hardware_threads = std::thread::hardware_concurrency(); - unsigned long const num_threads= - std::min(hardware_threads!=0?hardware_threads:2,max_threads); + unsigned long const num_threads = + std::min(hardware_threads != 0 ? hardware_threads : 2, max_threads); - unsigned long const block_size=length/num_threads; + unsigned long const block_size = length / num_threads; - std::vector results(num_threads); - std::vector threads(num_threads-1); + std::vector results(num_threads); + std::vector threads(num_threads - 1); - Iterator block_start=first; - for(unsigned long i=0;i<(num_threads-1);++i) - { - Iterator block_end=block_start; - std::advance(block_end,block_size); - threads[i]=std::thread( - accumulate_block(), - block_start,block_end,std::ref(results[i])); - block_start=block_end; - } - accumulate_block()(block_start,last,results[num_threads-1]); - - std::for_each(threads.begin(),threads.end(), - std::mem_fn(&std::thread::join)); + Iterator block_start = first; + for (unsigned long i = 0; i < (num_threads - 1); ++i) { + Iterator block_end = block_start; + std::advance(block_end, block_size); + threads[i] = std::thread(accumulate_block(), + block_start, + block_end, + std::ref(results[i])); + block_start = block_end; + } + accumulate_block()(block_start, last, results[num_threads - 1]); - return std::accumulate(results.begin(),results.end(),init); + std::for_each( + threads.begin(), threads.end(), std::mem_fn(&std::thread::join)); + + return std::accumulate(results.begin(), results.end(), init); } -int main() +int +main() { - std::vector vi; - for(int i=0;i<10;++i) - { - vi.push_back(10); - } - int sum=parallel_accumulate(vi.begin(),vi.end(),5); - std::cout<<"sum="< vi; + for (int i = 0; i < 10; ++i) { + vi.push_back(10); + } + int sum = parallel_accumulate(vi.begin(), vi.end(), 5); + std::cout << "sum=" << sum << std::endl; } diff --git a/source/listing_3.1.cpp b/source/listing_3.1.cpp index 772affb..01179de 100644 --- a/source/listing_3.1.cpp +++ b/source/listing_3.1.cpp @@ -1,26 +1,30 @@ +#include #include #include -#include std::list some_list; std::mutex some_mutex; -void add_to_list(int new_value) +void +add_to_list(int new_value) { - std::lock_guard guard(some_mutex); - some_list.push_back(new_value); + std::lock_guard guard(some_mutex); + some_list.push_back(new_value); } -bool list_contains(int value_to_find) +bool +list_contains(int value_to_find) { - std::lock_guard guard(some_mutex); - return std::find(some_list.begin(),some_list.end(),value_to_find) - != some_list.end(); + std::lock_guard guard(some_mutex); + return std::find(some_list.begin(), some_list.end(), value_to_find) != + some_list.end(); } #include -int main() +int +main() { - add_to_list(42); - std::cout<<"contains(1)="< -class threadsafe_stack -{ +template +class threadsafe_stack { private: - std::stack data; - mutable std::mutex m; -public: - threadsafe_stack(){} - threadsafe_stack(const threadsafe_stack& other) - { - std::lock_guard lock(other.m); - data=other.data; - } - threadsafe_stack& operator=(const threadsafe_stack&) = delete; + std::stack data; + mutable std::mutex m; - void push(T new_value) - { - std::lock_guard lock(m); - data.push(new_value); - } - std::shared_ptr pop() - { - std::lock_guard lock(m); - if(data.empty()) throw empty_stack(); - std::shared_ptr const res(std::make_shared(data.top())); - data.pop(); - return res; - } - void pop(T& value) - { - std::lock_guard lock(m); - if(data.empty()) throw empty_stack(); - value=data.top(); - data.pop(); - } - bool empty() const - { - std::lock_guard lock(m); - return data.empty(); - } +public: + threadsafe_stack() {} + threadsafe_stack(const threadsafe_stack& other) + { + std::lock_guard lock(other.m); + data = other.data; + } + threadsafe_stack& operator=(const threadsafe_stack&) = delete; + + void push(T new_value) + { + std::lock_guard lock(m); + data.push(new_value); + } + std::shared_ptr pop() + { + std::lock_guard lock(m); + if (data.empty()) + throw empty_stack(); + std::shared_ptr const res(std::make_shared(data.top())); + data.pop(); + return res; + } + void pop(T& value) + { + std::lock_guard lock(m); + if (data.empty()) + throw empty_stack(); + value = data.top(); + data.pop(); + } + bool empty() const + { + std::lock_guard lock(m); + return data.empty(); + } }; -int main() +int +main() { - threadsafe_stack si; - si.push(5); - si.pop(); - if(!si.empty()) - { - int x; - si.pop(x); - } - + threadsafe_stack si; + si.push(5); + si.pop(); + if (!si.empty()) { + int x; + si.pop(x); + } } diff --git a/source/listing_3.6.cpp b/source/listing_3.6.cpp index e2a48fd..beeead5 100644 --- a/source/listing_3.6.cpp +++ b/source/listing_3.6.cpp @@ -1,29 +1,33 @@ #include -class some_big_object -{}; - -void swap(some_big_object& lhs,some_big_object& rhs) -{} - -class X -{ -private: - some_big_object some_detail; - mutable std::mutex m; -public: - X(some_big_object const& sd):some_detail(sd){} - - friend void swap(X& lhs, X& rhs) - { - if(&lhs==&rhs) - return; - std::lock(lhs.m,rhs.m); - std::lock_guard lock_a(lhs.m,std::adopt_lock); - std::lock_guard lock_b(rhs.m,std::adopt_lock); - swap(lhs.some_detail,rhs.some_detail); - } +class some_big_object { }; -int main() -{} +void +swap(some_big_object& lhs, some_big_object& rhs) +{ +} + +class X { +private: + some_big_object some_detail; + mutable std::mutex m; + +public: + X(some_big_object const& sd) : some_detail(sd) {} + + friend void swap(X& lhs, X& rhs) + { + if (&lhs == &rhs) + return; + std::lock(lhs.m, rhs.m); + std::lock_guard lock_a(lhs.m, std::adopt_lock); + std::lock_guard lock_b(rhs.m, std::adopt_lock); + swap(lhs.some_detail, rhs.some_detail); + } +}; + +int +main() +{ +} diff --git a/source/listing_3.7.cpp b/source/listing_3.7.cpp index 002e71b..74c95bc 100644 --- a/source/listing_3.7.cpp +++ b/source/listing_3.7.cpp @@ -1,64 +1,68 @@ #include -class hierarchical_mutex -{ +class hierarchical_mutex { public: - explicit hierarchical_mutex(unsigned level) - {} - - void lock() - {} - void unlock() - {} -}; + explicit hierarchical_mutex(unsigned level) {} + void lock() {} + void unlock() {} +}; hierarchical_mutex high_level_mutex(10000); hierarchical_mutex low_level_mutex(5000); -int do_low_level_stuff() +int +do_low_level_stuff() { - return 42; + return 42; } - -int low_level_func() +int +low_level_func() { - std::lock_guard lk(low_level_mutex); - return do_low_level_stuff(); + std::lock_guard lk(low_level_mutex); + return do_low_level_stuff(); } -void high_level_stuff(int some_param) -{} - - -void high_level_func() +void +high_level_stuff(int some_param) { - std::lock_guard lk(high_level_mutex); - high_level_stuff(low_level_func()); } -void thread_a() +void +high_level_func() { - high_level_func(); + std::lock_guard lk(high_level_mutex); + high_level_stuff(low_level_func()); +} + +void +thread_a() +{ + high_level_func(); } hierarchical_mutex other_mutex(100); -void do_other_stuff() -{} - - -void other_stuff() +void +do_other_stuff() { - high_level_func(); - do_other_stuff(); } -void thread_b() +void +other_stuff() { - std::lock_guard lk(other_mutex); - other_stuff(); + high_level_func(); + do_other_stuff(); } -int main() -{} +void +thread_b() +{ + std::lock_guard lk(other_mutex); + other_stuff(); +} + +int +main() +{ +} diff --git a/source/listing_3.8.cpp b/source/listing_3.8.cpp index a1f18aa..071b7a7 100644 --- a/source/listing_3.8.cpp +++ b/source/listing_3.8.cpp @@ -1,56 +1,55 @@ #include #include -class hierarchical_mutex -{ - std::mutex internal_mutex; - unsigned long const hierarchy_value; - unsigned long previous_hierarchy_value; - static thread_local unsigned long this_thread_hierarchy_value; +class hierarchical_mutex { + std::mutex internal_mutex; + unsigned long const hierarchy_value; + unsigned long previous_hierarchy_value; + static thread_local unsigned long this_thread_hierarchy_value; - void check_for_hierarchy_violation() - { - if(this_thread_hierarchy_value <= hierarchy_value) - { - throw std::logic_error("mutex hierarchy violated"); - } - } - void update_hierarchy_value() - { - previous_hierarchy_value=this_thread_hierarchy_value; - this_thread_hierarchy_value=hierarchy_value; + void check_for_hierarchy_violation() + { + if (this_thread_hierarchy_value <= hierarchy_value) { + throw std::logic_error("mutex hierarchy violated"); } + } + void update_hierarchy_value() + { + previous_hierarchy_value = this_thread_hierarchy_value; + this_thread_hierarchy_value = hierarchy_value; + } + public: - explicit hierarchical_mutex(unsigned long value): - hierarchy_value(value), - previous_hierarchy_value(0) - {} - void lock() - { - check_for_hierarchy_violation(); - internal_mutex.lock(); - update_hierarchy_value(); - } - void unlock() - { - this_thread_hierarchy_value=previous_hierarchy_value; - internal_mutex.unlock(); - } - bool try_lock() - { - check_for_hierarchy_violation(); - if(!internal_mutex.try_lock()) - return false; - update_hierarchy_value(); - return true; - } + explicit hierarchical_mutex(unsigned long value) + : hierarchy_value(value), previous_hierarchy_value(0) + { + } + void lock() + { + check_for_hierarchy_violation(); + internal_mutex.lock(); + update_hierarchy_value(); + } + void unlock() + { + this_thread_hierarchy_value = previous_hierarchy_value; + internal_mutex.unlock(); + } + bool try_lock() + { + check_for_hierarchy_violation(); + if (!internal_mutex.try_lock()) + return false; + update_hierarchy_value(); + return true; + } }; -thread_local unsigned long - hierarchical_mutex::this_thread_hierarchy_value(ULONG_MAX); +thread_local unsigned long hierarchical_mutex::this_thread_hierarchy_value( + ULONG_MAX); -int main() +int +main() { - hierarchical_mutex m1(42); - hierarchical_mutex m2(2000); - + hierarchical_mutex m1(42); + hierarchical_mutex m2(2000); } diff --git a/source/listing_3.9.cpp b/source/listing_3.9.cpp index 807acbe..9678513 100644 --- a/source/listing_3.9.cpp +++ b/source/listing_3.9.cpp @@ -1,29 +1,33 @@ #include -class some_big_object -{}; - -void swap(some_big_object& lhs,some_big_object& rhs) -{} - -class X -{ -private: - some_big_object some_detail; - mutable std::mutex m; -public: - X(some_big_object const& sd):some_detail(sd){} - - friend void swap(X& lhs, X& rhs) - { - if(&lhs==&rhs) - return; - std::unique_lock lock_a(lhs.m,std::defer_lock); - std::unique_lock lock_b(rhs.m,std::defer_lock); - std::lock(lock_a,lock_b); - swap(lhs.some_detail,rhs.some_detail); - } +class some_big_object { }; -int main() -{} +void +swap(some_big_object& lhs, some_big_object& rhs) +{ +} + +class X { +private: + some_big_object some_detail; + mutable std::mutex m; + +public: + X(some_big_object const& sd) : some_detail(sd) {} + + friend void swap(X& lhs, X& rhs) + { + if (&lhs == &rhs) + return; + std::unique_lock lock_a(lhs.m, std::defer_lock); + std::unique_lock lock_b(rhs.m, std::defer_lock); + std::lock(lock_a, lock_b); + swap(lhs.some_detail, rhs.some_detail); + } +}; + +int +main() +{ +} diff --git a/source/listing_4.1.cpp b/source/listing_4.1.cpp index 5ede423..b71a41d 100644 --- a/source/listing_4.1.cpp +++ b/source/listing_4.1.cpp @@ -1,64 +1,70 @@ -#include #include -#include +#include #include +#include -bool more_data_to_prepare() +bool +more_data_to_prepare() { - return false; + return false; } -struct data_chunk -{}; +struct data_chunk { +}; -data_chunk prepare_data() +data_chunk +prepare_data() { - return data_chunk(); + return data_chunk(); } -void process(data_chunk&) -{} - -bool is_last_chunk(data_chunk&) +void +process(data_chunk&) { - return true; +} + +bool +is_last_chunk(data_chunk&) +{ + return true; } std::mutex mut; std::queue data_queue; std::condition_variable data_cond; -void data_preparation_thread() +void +data_preparation_thread() { - while(more_data_to_prepare()) - { - data_chunk const data=prepare_data(); - std::lock_guard lk(mut); - data_queue.push(data); - data_cond.notify_one(); - } + while (more_data_to_prepare()) { + data_chunk const data = prepare_data(); + std::lock_guard lk(mut); + data_queue.push(data); + data_cond.notify_one(); + } } -void data_processing_thread() +void +data_processing_thread() { - while(true) - { - std::unique_lock lk(mut); - data_cond.wait(lk,[]{return !data_queue.empty();}); - data_chunk data=data_queue.front(); - data_queue.pop(); - lk.unlock(); - process(data); - if(is_last_chunk(data)) - break; - } + while (true) { + std::unique_lock lk(mut); + data_cond.wait(lk, [] { return !data_queue.empty(); }); + data_chunk data = data_queue.front(); + data_queue.pop(); + lk.unlock(); + process(data); + if (is_last_chunk(data)) + break; + } } -int main() +int +main() { - std::thread t1(data_preparation_thread); - std::thread t2(data_processing_thread); - - t1.join(); - t2.join(); + std::thread t1(data_preparation_thread); + std::thread t2(data_processing_thread); + + t1.join(); + t2.join(); } diff --git a/source/listing_4.10.cpp b/source/listing_4.10.cpp index 9eadddd..40766ba 100644 --- a/source/listing_4.10.cpp +++ b/source/listing_4.10.cpp @@ -1,27 +1,22 @@ #include -void process_connections(connection_set& connections) +void +process_connections(connection_set& connections) { - while(!done(connections)) - { - for(connection_iterator - connection=connections.begin(),end=connections.end(); - connection!=end; - ++connection) - { - if(connection->has_incoming_data()) - { - data_packet data=connection->incoming(); - std::promise& p= - connection->get_promise(data.id); - p.set_value(data.payload); - } - if(connection->has_outgoing_data()) - { - outgoing_packet data= - connection->top_of_outgoing_queue(); - connection->send(data.payload); - data.promise.set_value(true); - } - } + while (!done(connections)) { + for (connection_iterator connection = connections.begin(), + end = connections.end(); + connection != end; + ++connection) { + if (connection->has_incoming_data()) { + data_packet data = connection->incoming(); + std::promise& p = connection->get_promise(data.id); + p.set_value(data.payload); + } + if (connection->has_outgoing_data()) { + outgoing_packet data = connection->top_of_outgoing_queue(); + connection->send(data.payload); + data.promise.set_value(true); + } } + } } diff --git a/source/listing_4.11.cpp b/source/listing_4.11.cpp index 8d22cb6..e5372c9 100644 --- a/source/listing_4.11.cpp +++ b/source/listing_4.11.cpp @@ -1,18 +1,18 @@ +#include #include #include -#include std::condition_variable cv; bool done; std::mutex m; -bool wait_loop() +bool +wait_loop() { - auto const timeout= std::chrono::steady_clock::now()+ - std::chrono::milliseconds(500); - std::unique_lock lk(m); - while(!done) - { - if(cv.wait_until(lk,timeout)==std::cv_status::timeout) - break; - } - return done; + auto const timeout = + std::chrono::steady_clock::now() + std::chrono::milliseconds(500); + std::unique_lock lk(m); + while (!done) { + if (cv.wait_until(lk, timeout) == std::cv_status::timeout) + break; + } + return done; } diff --git a/source/listing_4.12.cpp b/source/listing_4.12.cpp index f4592ff..ea5b4a1 100644 --- a/source/listing_4.12.cpp +++ b/source/listing_4.12.cpp @@ -1,24 +1,21 @@ -template -std::list sequential_quick_sort(std::list input) +template +std::list +sequential_quick_sort(std::list input) { - if(input.empty()) - { - return input; - } - std::list result; - result.splice(result.begin(),input,input.begin()); - T const& pivot=*result.begin(); - auto divide_point=std::partition(input.begin(),input.end(), - [&](T const& t){return t lower_part; - lower_part.splice(lower_part.end(),input,input.begin(), - divide_point); - auto new_lower( - sequential_quick_sort(std::move(lower_part))); - auto new_higher( - sequential_quick_sort(std::move(input))); - result.splice(result.end(),new_higher); - Using synchronization of operations to simplify code - result.splice(result.begin(),new_lower); - return result; + if (input.empty()) { + return input; + } + std::list result; + result.splice(result.begin(), input, input.begin()); + T const& pivot = *result.begin(); + auto divide_point = std::partition( + input.begin(), input.end(), [&](T const& t) { return t < pivot; }); + std::list lower_part; + lower_part.splice(lower_part.end(), input, input.begin(), divide_point); + auto new_lower(sequential_quick_sort(std::move(lower_part))); + auto new_higher(sequential_quick_sort(std::move(input))); + result.splice(result.end(), new_higher); + Using synchronization of operations to simplify code result.splice( + result.begin(), new_lower); + return result; } diff --git a/source/listing_4.13.cpp b/source/listing_4.13.cpp index ae87d08..3fe989e 100644 --- a/source/listing_4.13.cpp +++ b/source/listing_4.13.cpp @@ -1,23 +1,21 @@ -template -std::list parallel_quick_sort(std::list input) +template +std::list +parallel_quick_sort(std::list input) { - if(input.empty()) - { - return input; - } - std::list result; - result.splice(result.begin(),input,input.begin()); - T const& pivot=*result.begin(); - auto divide_point=std::partition(input.begin(),input.end(), - [&](T const& t){return t lower_part; - lower_part.splice(lower_part.end(),input,input.begin(), - divide_point); - std::future > new_lower( - std::async(¶llel_quick_sort,std::move(lower_part))); - auto new_higher( - parallel_quick_sort(std::move(input))); - result.splice(result.end(),new_higher); - result.splice(result.begin(),new_lower.get()); - return result; + if (input.empty()) { + return input; + } + std::list result; + result.splice(result.begin(), input, input.begin()); + T const& pivot = *result.begin(); + auto divide_point = std::partition( + input.begin(), input.end(), [&](T const& t) { return t < pivot; }); + std::list lower_part; + lower_part.splice(lower_part.end(), input, input.begin(), divide_point); + std::future> new_lower( + std::async(¶llel_quick_sort, std::move(lower_part))); + auto new_higher(parallel_quick_sort(std::move(input))); + result.splice(result.end(), new_higher); + result.splice(result.begin(), new_lower.get()); + return result; } diff --git a/source/listing_4.14.cpp b/source/listing_4.14.cpp index e70c58d..7698b0b 100644 --- a/source/listing_4.14.cpp +++ b/source/listing_4.14.cpp @@ -1,12 +1,11 @@ -template +template std::future::type> -spawn_task(F&& f,A&& a) +spawn_task(F&& f, A&& a) { - typedef std::result_of::type result_type; - std::packaged_task - task(std::move(f)); - std::future res(task.get_future()); - std::thread t(std::move(task),std::move(a)); - t.detach(); - return res; + typedef std::result_of::type result_type; + std::packaged_task task(std::move(f)); + std::future res(task.get_future()); + std::thread t(std::move(task), std::move(a)); + t.detach(); + return res; } diff --git a/source/listing_4.15.cpp b/source/listing_4.15.cpp index 9868de8..c973793 100644 --- a/source/listing_4.15.cpp +++ b/source/listing_4.15.cpp @@ -1,43 +1,35 @@ -struct card_inserted -{ - std::string account; +struct card_inserted { + std::string account; }; -class atm -{ - messaging::receiver incoming; - messaging::sender bank; - messaging::sender interface_hardware; - void (atm::*state)(); - std::string account; - std::string pin; - void waiting_for_card() - { - interface_hardware.send(display_enter_card()); - incoming.wait() - .handle( - [&](card_inserted const& msg) - { - account=msg.account; - pin=""; - interface_hardware.send(display_enter_pin()); - state=&atm::getting_pin; - } - ); - } - void getting_pin(); +class atm { + messaging::receiver incoming; + messaging::sender bank; + messaging::sender interface_hardware; + void (atm::*state)(); + std::string account; + std::string pin; + void waiting_for_card() + { + interface_hardware.send(display_enter_card()); + incoming.wait().handle([&](card_inserted const& msg) { + account = msg.account; + pin = ""; + interface_hardware.send(display_enter_pin()); + state = &atm::getting_pin; + }); + } + void getting_pin(); + public: - void run() - { - state=&atm::waiting_for_card; - try - { - for(;;) - { - (this->*state)(); - } - } - catch(messaging::close_queue const&) - { - } + void run() + { + state = &atm::waiting_for_card; + try { + for (;;) { + (this->*state)(); + } } + catch (messaging::close_queue const&) { + } + } }; diff --git a/source/listing_4.16.cpp b/source/listing_4.16.cpp index 499bb91..3e4aeef 100644 --- a/source/listing_4.16.cpp +++ b/source/listing_4.16.cpp @@ -1,31 +1,20 @@ -void atm::getting_pin() +void +atm::getting_pin() { - incoming.wait() - .handle( - [&](digit_pressed const& msg) - { - unsigned const pin_length=4; - pin+=msg.digit; - if(pin.length()==pin_length) - { - bank.send(verify_pin(account,pin,incoming)); - state=&atm::verifying_pin; - } - } - ) - .handle( - [&](clear_last_pressed const& msg) - { - if(!pin.empty()) - { - pin.resize(pin.length()-1); - } - } - ) - .handle( - [&](cancel_pressed const& msg) - { - state=&atm::done_processing; - } - ); + incoming.wait() + .handle([&](digit_pressed const& msg) { + unsigned const pin_length = 4; + pin += msg.digit; + if (pin.length() == pin_length) { + bank.send(verify_pin(account, pin, incoming)); + state = &atm::verifying_pin; + } + }) + .handle([&](clear_last_pressed const& msg) { + if (!pin.empty()) { + pin.resize(pin.length() - 1); + } + }) + .handle( + [&](cancel_pressed const& msg) { state = &atm::done_processing; }); } diff --git a/source/listing_4.2.cpp b/source/listing_4.2.cpp index a413a22..a3926b3 100644 --- a/source/listing_4.2.cpp +++ b/source/listing_4.2.cpp @@ -1,30 +1,36 @@ -template > +template > class queue { public: - explicit queue(const Container&); - explicit queue(Container&& = Container()); - queue(queue&& q); + explicit queue(const Container&); + explicit queue(Container&& = Container()); + queue(queue&& q); - template explicit queue(const Alloc&); - template queue(const Container&, const Alloc&); - template queue(Container&&, const Alloc&); - template queue(queue&&, const Alloc&); + template + explicit queue(const Alloc&); + template + queue(const Container&, const Alloc&); + template + queue(Container&&, const Alloc&); + template + queue(queue&&, const Alloc&); - queue& operator=(queue&& q); - void swap(queue&& q); + queue& operator=(queue&& q); + void swap(queue&& q); - bool empty() const; - size_type size() const; + bool empty() const; + size_type size() const; - T& front(); - const T& front() const; - T& back(); - const T& back() const; + T& front(); + const T& front() const; + T& back(); + const T& back() const; - void push(const T& x); - void push(T&& x); - void pop(); + void push(const T& x); + void push(T&& x); + void pop(); }; -int main() -{} +int +main() +{ +} diff --git a/source/listing_4.3.cpp b/source/listing_4.3.cpp index d2ea1d4..9d8f723 100644 --- a/source/listing_4.3.cpp +++ b/source/listing_4.3.cpp @@ -1,22 +1,23 @@ #include -template -class threadsafe_queue -{ +template +class threadsafe_queue { public: - threadsafe_queue(); - threadsafe_queue(const threadsafe_queue&); - threadsafe_queue& operator=(const threadsafe_queue&) = delete; + threadsafe_queue(); + threadsafe_queue(const threadsafe_queue&); + threadsafe_queue& operator=(const threadsafe_queue&) = delete; - void push(T new_value); - - bool try_pop(T& value); - std::shared_ptr try_pop(); + void push(T new_value); - void wait_and_pop(T& value); - std::shared_ptr wait_and_pop(); + bool try_pop(T& value); + std::shared_ptr try_pop(); - bool empty() const; + void wait_and_pop(T& value); + std::shared_ptr wait_and_pop(); + + bool empty() const; }; -int main() -{} +int +main() +{ +} diff --git a/source/listing_4.4.cpp b/source/listing_4.4.cpp index 672d141..0a9617d 100644 --- a/source/listing_4.4.cpp +++ b/source/listing_4.4.cpp @@ -1,33 +1,32 @@ -#include #include +#include #include -template -class threadsafe_queue -{ +template +class threadsafe_queue { private: - std::mutex mut; - std::queue data_queue; - std::condition_variable data_cond; -public: - void push(T new_value) - { - std::lock_guard lk(mut); - data_queue.push(new_value); - data_cond.notify_one(); - } + std::mutex mut; + std::queue data_queue; + std::condition_variable data_cond; - void wait_and_pop(T& value) - { - std::unique_lock lk(mut); - data_cond.wait(lk,[this]{return !data_queue.empty();}); - value=data_queue.front(); - data_queue.pop(); - } +public: + void push(T new_value) + { + std::lock_guard lk(mut); + data_queue.push(new_value); + data_cond.notify_one(); + } + + void wait_and_pop(T& value) + { + std::unique_lock lk(mut); + data_cond.wait(lk, [this] { return !data_queue.empty(); }); + value = data_queue.front(); + data_queue.pop(); + } }; - -struct data_chunk -{}; +struct data_chunk { +}; data_chunk prepare_data(); bool more_data_to_prepare(); @@ -36,23 +35,23 @@ bool is_last_chunk(data_chunk); threadsafe_queue data_queue; -void data_preparation_thread() +void +data_preparation_thread() { - while(more_data_to_prepare()) - { - data_chunk const data=prepare_data(); - data_queue.push(data); - } + while (more_data_to_prepare()) { + data_chunk const data = prepare_data(); + data_queue.push(data); + } } -void data_processing_thread() +void +data_processing_thread() { - while(true) - { - data_chunk data; - data_queue.wait_and_pop(data); - process(data); - if(is_last_chunk(data)) - break; - } + while (true) { + data_chunk data; + data_queue.wait_and_pop(data); + process(data); + if (is_last_chunk(data)) + break; + } } diff --git a/source/listing_4.5.cpp b/source/listing_4.5.cpp index 0e78979..b53ddce 100644 --- a/source/listing_4.5.cpp +++ b/source/listing_4.5.cpp @@ -1,73 +1,74 @@ -#include #include -#include #include +#include +#include -template -class threadsafe_queue -{ +template +class threadsafe_queue { private: - mutable std::mutex mut; - std::queue data_queue; - std::condition_variable data_cond; + mutable std::mutex mut; + std::queue data_queue; + std::condition_variable data_cond; + public: - threadsafe_queue() - {} - threadsafe_queue(threadsafe_queue const& other) - { - std::lock_guard lk(other.mut); - data_queue=other.data_queue; - } + threadsafe_queue() {} + threadsafe_queue(threadsafe_queue const& other) + { + std::lock_guard lk(other.mut); + data_queue = other.data_queue; + } - void push(T new_value) - { - std::lock_guard lk(mut); - data_queue.push(new_value); - data_cond.notify_one(); - } + void push(T new_value) + { + std::lock_guard lk(mut); + data_queue.push(new_value); + data_cond.notify_one(); + } - void wait_and_pop(T& value) - { - std::unique_lock lk(mut); - data_cond.wait(lk,[this]{return !data_queue.empty();}); - value=data_queue.front(); - data_queue.pop(); - } + void wait_and_pop(T& value) + { + std::unique_lock lk(mut); + data_cond.wait(lk, [this] { return !data_queue.empty(); }); + value = data_queue.front(); + data_queue.pop(); + } - std::shared_ptr wait_and_pop() - { - std::unique_lock lk(mut); - data_cond.wait(lk,[this]{return !data_queue.empty();}); - std::shared_ptr res(std::make_shared(data_queue.front())); - data_queue.pop(); - return res; - } + std::shared_ptr wait_and_pop() + { + std::unique_lock lk(mut); + data_cond.wait(lk, [this] { return !data_queue.empty(); }); + std::shared_ptr res(std::make_shared(data_queue.front())); + data_queue.pop(); + return res; + } - bool try_pop(T& value) - { - std::lock_guard lk(mut); - if(data_queue.empty) - return false; - value=data_queue.front(); - data_queue.pop(); - } + bool try_pop(T& value) + { + std::lock_guard lk(mut); + if (data_queue.empty) + return false; + value = data_queue.front(); + data_queue.pop(); + } - std::shared_ptr try_pop() - { - std::lock_guard lk(mut); - if(data_queue.empty()) - return std::shared_ptr(); - std::shared_ptr res(std::make_shared(data_queue.front())); - data_queue.pop(); - return res; - } + std::shared_ptr try_pop() + { + std::lock_guard lk(mut); + if (data_queue.empty()) + return std::shared_ptr(); + std::shared_ptr res(std::make_shared(data_queue.front())); + data_queue.pop(); + return res; + } - bool empty() const - { - std::lock_guard lk(mut); - return data_queue.empty(); - } + bool empty() const + { + std::lock_guard lk(mut); + return data_queue.empty(); + } }; -int main() -{} +int +main() +{ +} diff --git a/source/listing_4.6.cpp b/source/listing_4.6.cpp index 3965eb1..ae2a398 100644 --- a/source/listing_4.6.cpp +++ b/source/listing_4.6.cpp @@ -1,16 +1,20 @@ #include #include -int find_the_answer_to_ltuae() +int +find_the_answer_to_ltuae() { - return 42; + return 42; } -void do_other_stuff() -{} - -int main() +void +do_other_stuff() { - std::future the_answer=std::async(find_the_answer_to_ltuae); - do_other_stuff(); - std::cout<<"The answer is "< the_answer = std::async(find_the_answer_to_ltuae); + do_other_stuff(); + std::cout << "The answer is " << the_answer.get() << std::endl; } diff --git a/source/listing_4.7.cpp b/source/listing_4.7.cpp index 05caa06..b702b2b 100644 --- a/source/listing_4.7.cpp +++ b/source/listing_4.7.cpp @@ -1,34 +1,30 @@ -#include #include +#include -struct X -{ - void foo(int,std::string const&); - std::string bar(std::string const&); +struct X { + void foo(int, std::string const&); + std::string bar(std::string const&); }; - X x; -auto f1=std::async(&X::foo,&x,42,"hello"); -auto f2=std::async(&X::bar,x,"goodbye"); +auto f1 = std::async(&X::foo, &x, 42, "hello"); +auto f2 = std::async(&X::bar, x, "goodbye"); -struct Y -{ - double operator()(double); +struct Y { + double operator()(double); }; Y y; -auto f3=std::async(Y(),3.141); -auto f4=std::async(std::ref(y),2.718); +auto f3 = std::async(Y(), 3.141); +auto f4 = std::async(std::ref(y), 2.718); X baz(X&); -auto f6=std::async(baz,std::ref(x)); -class move_only -{ +auto f6 = std::async(baz, std::ref(x)); +class move_only { public: - move_only(); - move_only(move_only&&); - move_only(move_only const&) = delete; - move_only& operator=(move_only&&); - move_only& operator=(move_only const&) = delete; - void operator()(); + move_only(); + move_only(move_only&&); + move_only(move_only const&) = delete; + move_only& operator =(move_only&&); + move_only& operator=(move_only const&) = delete; + void operator()(); }; -auto f5=std::async(move_only()); +auto f5 = std::async(move_only()); diff --git a/source/listing_4.8.cpp b/source/listing_4.8.cpp index a3f46c9..9d565d3 100644 --- a/source/listing_4.8.cpp +++ b/source/listing_4.8.cpp @@ -1,9 +1,8 @@ -template<> -class packaged_task*,int)> -{ +template <> +class packaged_task*, int)> { public: - template - explicit packaged_task(Callable&& f); - std::future get_future(); - void operator()(std::vector*,int); + template + explicit packaged_task(Callable&& f); + std::future get_future(); + void operator()(std::vector*, int); }; diff --git a/source/listing_4.9.cpp b/source/listing_4.9.cpp index 0b86a3f..496a0fc 100644 --- a/source/listing_4.9.cpp +++ b/source/listing_4.9.cpp @@ -1,40 +1,41 @@ #include -#include #include +#include #include #include std::mutex m; -std::deque > tasks; +std::deque> tasks; bool gui_shutdown_message_received(); void get_and_process_gui_message(); -void gui_thread() +void +gui_thread() { - while(!gui_shutdown_message_received()) + while (!gui_shutdown_message_received()) { + get_and_process_gui_message(); + std::packaged_task task; { - get_and_process_gui_message(); - std::packaged_task task; - { - std::lock_guard lk(m); - if(tasks.empty()) - continue; - task=std::move(tasks.front()); - tasks.pop_front(); - } - task(); + std::lock_guard lk(m); + if (tasks.empty()) + continue; + task = std::move(tasks.front()); + tasks.pop_front(); } + task(); + } } std::thread gui_bg_thread(gui_thread); -template -std::future post_task_for_gui_thread(Func f) +template +std::future +post_task_for_gui_thread(Func f) { - std::packaged_task task(f); - std::future res=task.get_future(); - std::lock_guard lk(m); - tasks.push_back(std::move(task)); - return res; + std::packaged_task task(f); + std::future res = task.get_future(); + std::lock_guard lk(m); + tasks.push_back(std::move(task)); + return res; } diff --git a/source/listing_5.1.cpp b/source/listing_5.1.cpp index e2441b3..52c8acb 100644 --- a/source/listing_5.1.cpp +++ b/source/listing_5.1.cpp @@ -1,16 +1,12 @@ -class spinlock_mutex -{ - std::atomic_flag flag; +class spinlock_mutex { + std::atomic_flag flag; + public: - spinlock_mutex(): - flag(ATOMIC_FLAG_INIT) - {} - void lock() - { - while(flag.test_and_set(std::memory_order_acquire)); - } - void unlock() - { - flag.clear(std::memory_order_release); - } + spinlock_mutex() : flag(ATOMIC_FLAG_INIT) {} + void lock() + { + while (flag.test_and_set(std::memory_order_acquire)) + ; + } + void unlock() { flag.clear(std::memory_order_release); } }; diff --git a/source/listing_5.10.cpp b/source/listing_5.10.cpp index 2de655f..987c270 100644 --- a/source/listing_5.10.cpp +++ b/source/listing_5.10.cpp @@ -1,39 +1,40 @@ +#include +#include #include #include -#include -#include -struct X -{ - int i; - std::string s; +struct X { + int i; + std::string s; }; std::atomic p; std::atomic a; -void create_x() +void +create_x() { - X* x=new X; - x->i=42; - x->s="hello"; - a.store(99,std::memory_order_relaxed); - p.store(x,std::memory_order_release); + X* x = new X; + x->i = 42; + x->s = "hello"; + a.store(99, std::memory_order_relaxed); + p.store(x, std::memory_order_release); } -void use_x() +void +use_x() { - X* x; - while(!(x=p.load(std::memory_order_consume))) - std::this_thread::sleep_for(std::chrono::microseconds(1)); - assert(x->i==42); - assert(x->s=="hello"); - assert(a.load(std::memory_order_relaxed)==99); + X* x; + while (!(x = p.load(std::memory_order_consume))) + std::this_thread::sleep_for(std::chrono::microseconds(1)); + assert(x->i == 42); + assert(x->s == "hello"); + assert(a.load(std::memory_order_relaxed) == 99); } -int main() +int +main() { - std::thread t1(create_x); - std::thread t2(use_x); - t1.join(); - t2.join(); + std::thread t1(create_x); + std::thread t2(use_x); + t1.join(); + t2.join(); } - diff --git a/source/listing_5.11.cpp b/source/listing_5.11.cpp index deef694..e9eced9 100644 --- a/source/listing_5.11.cpp +++ b/source/listing_5.11.cpp @@ -4,38 +4,38 @@ std::vector queue_data; std::atomic count; -void populate_queue() +void +populate_queue() { - unsigned const number_of_items=20; - queue_data.clear(); - for(unsigned i=0;i #include #include -#include -std::atomic x,y; +std::atomic x, y; std::atomic z; -void write_x_then_y() +void +write_x_then_y() { - x.store(true,std::memory_order_relaxed); - std::atomic_thread_fence(std::memory_order_release); - y.store(true,std::memory_order_relaxed); + x.store(true, std::memory_order_relaxed); + std::atomic_thread_fence(std::memory_order_release); + y.store(true, std::memory_order_relaxed); } -void read_y_then_x() +void +read_y_then_x() { - while(!y.load(std::memory_order_relaxed)); - std::atomic_thread_fence(std::memory_order_acquire); - if(x.load(std::memory_order_relaxed)) - ++z; + while (!y.load(std::memory_order_relaxed)) + ; + std::atomic_thread_fence(std::memory_order_acquire); + if (x.load(std::memory_order_relaxed)) + ++z; } -int main() +int +main() { - x=false; - y=false; - z=0; - std::thread a(write_x_then_y); - std::thread b(read_y_then_x); - a.join(); - b.join(); - assert(z.load()!=0); + x = false; + y = false; + z = 0; + std::thread a(write_x_then_y); + std::thread b(read_y_then_x); + a.join(); + b.join(); + assert(z.load() != 0); } diff --git a/source/listing_5.13.cpp b/source/listing_5.13.cpp index a5de692..c7ec58d 100644 --- a/source/listing_5.13.cpp +++ b/source/listing_5.13.cpp @@ -1,34 +1,38 @@ +#include #include #include -#include -bool x=false; +bool x = false; std::atomic y; std::atomic z; -void write_x_then_y() +void +write_x_then_y() { - x=true; - std::atomic_thread_fence(std::memory_order_release); - y.store(true,std::memory_order_relaxed); + x = true; + std::atomic_thread_fence(std::memory_order_release); + y.store(true, std::memory_order_relaxed); } -void read_y_then_x() +void +read_y_then_x() { - while(!y.load(std::memory_order_relaxed)); - std::atomic_thread_fence(std::memory_order_acquire); - if(x) - ++z; + while (!y.load(std::memory_order_relaxed)) + ; + std::atomic_thread_fence(std::memory_order_acquire); + if (x) + ++z; } -int main() +int +main() { - x=false; - y=false; - z=0; - std::thread a(write_x_then_y); - std::thread b(read_y_then_x); - a.join(); - b.join(); - assert(z.load()!=0); + x = false; + y = false; + z = 0; + std::thread a(write_x_then_y); + std::thread b(read_y_then_x); + a.join(); + b.join(); + assert(z.load() != 0); } diff --git a/source/listing_5.2.cpp b/source/listing_5.2.cpp index 616bc71..8126da7 100644 --- a/source/listing_5.2.cpp +++ b/source/listing_5.2.cpp @@ -1,22 +1,23 @@ -#include #include -#include #include +#include #include +#include std::vector data; std::atomic_bool data_ready(false); -void reader_thread() +void +reader_thread() { - while(!data_ready.load()) - { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } - std::cout<<"The answer="< -void foo(int a,int b) +void +foo(int a, int b) { - std::cout< #include #include -#include -std::atomic x,y; +std::atomic x, y; std::atomic z; -void write_x() +void +write_x() { - x.store(true,std::memory_order_seq_cst); + x.store(true, std::memory_order_seq_cst); } -void write_y() +void +write_y() { - y.store(true,std::memory_order_seq_cst); + y.store(true, std::memory_order_seq_cst); } -void read_x_then_y() +void +read_x_then_y() { - while(!x.load(std::memory_order_seq_cst)); - if(y.load(std::memory_order_seq_cst)) - ++z; + while (!x.load(std::memory_order_seq_cst)) + ; + if (y.load(std::memory_order_seq_cst)) + ++z; } -void read_y_then_x() +void +read_y_then_x() { - while(!y.load(std::memory_order_seq_cst)); - if(x.load(std::memory_order_seq_cst)) - ++z; + while (!y.load(std::memory_order_seq_cst)) + ; + if (x.load(std::memory_order_seq_cst)) + ++z; } -int main() +int +main() { - x=false; - y=false; - z=0; - std::thread a(write_x); - std::thread b(write_y); - std::thread c(read_x_then_y); - std::thread d(read_y_then_x); - a.join(); - b.join(); - c.join(); - d.join(); - assert(z.load()!=0); + x = false; + y = false; + z = 0; + std::thread a(write_x); + std::thread b(write_y); + std::thread c(read_x_then_y); + std::thread d(read_y_then_x); + a.join(); + b.join(); + c.join(); + d.join(); + assert(z.load() != 0); } diff --git a/source/listing_5.5.cpp b/source/listing_5.5.cpp index 057d03b..fba1c4c 100644 --- a/source/listing_5.5.cpp +++ b/source/listing_5.5.cpp @@ -1,31 +1,35 @@ +#include #include #include -#include -std::atomic x,y; +std::atomic x, y; std::atomic z; -void write_x_then_y() +void +write_x_then_y() { - x.store(true,std::memory_order_relaxed); - y.store(true,std::memory_order_relaxed); + x.store(true, std::memory_order_relaxed); + y.store(true, std::memory_order_relaxed); } -void read_y_then_x() +void +read_y_then_x() { - while(!y.load(std::memory_order_relaxed)); - if(x.load(std::memory_order_relaxed)) - ++z; + while (!y.load(std::memory_order_relaxed)) + ; + if (x.load(std::memory_order_relaxed)) + ++z; } -int main() +int +main() { - x=false; - y=false; - z=0; - std::thread a(write_x_then_y); - std::thread b(read_y_then_x); - a.join(); - b.join(); - assert(z.load()!=0); + x = false; + y = false; + z = 0; + std::thread a(write_x_then_y); + std::thread b(read_y_then_x); + a.join(); + b.join(); + assert(z.load() != 0); } diff --git a/source/listing_5.6.cpp b/source/listing_5.6.cpp index e6045a5..18e7856 100644 --- a/source/listing_5.6.cpp +++ b/source/listing_5.6.cpp @@ -1,74 +1,72 @@ -#include #include #include +#include -std::atomic x(0),y(0),z(0); +std::atomic x(0), y(0), z(0); std::atomic go(false); -unsigned const loop_count=10; +unsigned const loop_count = 10; -struct read_values -{ - int x,y,z; +struct read_values { + int x, y, z; }; read_values values1[loop_count]; read_values values2[loop_count]; read_values values3[loop_count]; read_values values4[loop_count]; read_values values5[loop_count]; -void increment(std::atomic* var_to_inc,read_values* values) +void +increment(std::atomic* var_to_inc, read_values* values) { - while(!go) - std::this_thread::yield(); - for(unsigned i=0;istore(i+1,std::memory_order_relaxed); - std::this_thread::yield(); - } + while (!go) std::this_thread::yield(); + for (unsigned i = 0; i < loop_count; ++i) { + values[i].x = x.load(std::memory_order_relaxed); + values[i].y = y.load(std::memory_order_relaxed); + values[i].z = z.load(std::memory_order_relaxed); + var_to_inc->store(i + 1, std::memory_order_relaxed); + std::this_thread::yield(); + } } -void read_vals(read_values* values) +void +read_vals(read_values* values) { - while(!go) - std::this_thread::yield(); - for(unsigned i=0;i #include #include -#include -std::atomic x,y; +std::atomic x, y; std::atomic z; -void write_x() +void +write_x() { - x.store(true,std::memory_order_release); + x.store(true, std::memory_order_release); } -void write_y() +void +write_y() { - y.store(true,std::memory_order_release); + y.store(true, std::memory_order_release); } -void read_x_then_y() +void +read_x_then_y() { - while(!x.load(std::memory_order_acquire)); - if(y.load(std::memory_order_acquire)) - ++z; + while (!x.load(std::memory_order_acquire)) + ; + if (y.load(std::memory_order_acquire)) + ++z; } -void read_y_then_x() +void +read_y_then_x() { - while(!y.load(std::memory_order_acquire)); - if(x.load(std::memory_order_acquire)) - ++z; + while (!y.load(std::memory_order_acquire)) + ; + if (x.load(std::memory_order_acquire)) + ++z; } -int main() +int +main() { - x=false; - y=false; - z=0; - std::thread a(write_x); - std::thread b(write_y); - std::thread c(read_x_then_y); - std::thread d(read_y_then_x); - a.join(); - b.join(); - c.join(); - d.join(); - assert(z.load()!=0); + x = false; + y = false; + z = 0; + std::thread a(write_x); + std::thread b(write_y); + std::thread c(read_x_then_y); + std::thread d(read_y_then_x); + a.join(); + b.join(); + c.join(); + d.join(); + assert(z.load() != 0); } diff --git a/source/listing_5.8.cpp b/source/listing_5.8.cpp index 19c1612..ecd1f49 100644 --- a/source/listing_5.8.cpp +++ b/source/listing_5.8.cpp @@ -1,31 +1,35 @@ +#include #include #include -#include -std::atomic x,y; +std::atomic x, y; std::atomic z; -void write_x_then_y() +void +write_x_then_y() { - x.store(true,std::memory_order_relaxed); - y.store(true,std::memory_order_release); + x.store(true, std::memory_order_relaxed); + y.store(true, std::memory_order_release); } -void read_y_then_x() +void +read_y_then_x() { - while(!y.load(std::memory_order_acquire)); - if(x.load(std::memory_order_relaxed)) - ++z; + while (!y.load(std::memory_order_acquire)) + ; + if (x.load(std::memory_order_relaxed)) + ++z; } -int main() +int +main() { - x=false; - y=false; - z=0; - std::thread a(write_x_then_y); - std::thread b(read_y_then_x); - a.join(); - b.join(); - assert(z.load()!=0); + x = false; + y = false; + z = 0; + std::thread a(write_x_then_y); + std::thread b(read_y_then_x); + a.join(); + b.join(); + assert(z.load() != 0); } diff --git a/source/listing_5.9.cpp b/source/listing_5.9.cpp index 992ae56..fbb51ff 100644 --- a/source/listing_5.9.cpp +++ b/source/listing_5.9.cpp @@ -1,42 +1,48 @@ +#include #include #include -#include std::atomic data[5]; -std::atomic sync1(false),sync2(false); +std::atomic sync1(false), sync2(false); -void thread_1() +void +thread_1() { - data[0].store(42,std::memory_order_relaxed); - data[1].store(97,std::memory_order_relaxed); - data[2].store(17,std::memory_order_relaxed); - data[3].store(-141,std::memory_order_relaxed); - data[4].store(2003,std::memory_order_relaxed); - sync1.store(true,std::memory_order_release); + data[0].store(42, std::memory_order_relaxed); + data[1].store(97, std::memory_order_relaxed); + data[2].store(17, std::memory_order_relaxed); + data[3].store(-141, std::memory_order_relaxed); + data[4].store(2003, std::memory_order_relaxed); + sync1.store(true, std::memory_order_release); } -void thread_2() +void +thread_2() { - while(!sync1.load(std::memory_order_acquire)); - sync2.store(std::memory_order_release); + while (!sync1.load(std::memory_order_acquire)) + ; + sync2.store(std::memory_order_release); } -void thread_3() +void +thread_3() { - while(!sync2.load(std::memory_order_acquire)); - assert(data[0].load(std::memory_order_relaxed)==42); - assert(data[1].load(std::memory_order_relaxed)==97); - assert(data[2].load(std::memory_order_relaxed)==17); - assert(data[3].load(std::memory_order_relaxed)==-141); - assert(data[4].load(std::memory_order_relaxed)==2003); + while (!sync2.load(std::memory_order_acquire)) + ; + assert(data[0].load(std::memory_order_relaxed) == 42); + assert(data[1].load(std::memory_order_relaxed) == 97); + assert(data[2].load(std::memory_order_relaxed) == 17); + assert(data[3].load(std::memory_order_relaxed) == -141); + assert(data[4].load(std::memory_order_relaxed) == 2003); } -int main() +int +main() { - std::thread t1(thread_1); - std::thread t2(thread_2); - std::thread t3(thread_3); - t1.join(); - t2.join(); - t3.join(); + std::thread t1(thread_1); + std::thread t2(thread_2); + std::thread t3(thread_3); + t1.join(); + t2.join(); + t3.join(); } diff --git a/source/listing_6.1.cpp b/source/listing_6.1.cpp index 011938a..6750cbb 100644 --- a/source/listing_6.1.cpp +++ b/source/listing_6.1.cpp @@ -1,56 +1,52 @@ #include -#include -#include #include +#include +#include -struct empty_stack: std::exception -{ - const char* what() const throw() - { - return "empty stack"; - } +struct empty_stack : std::exception { + const char* what() const throw() { return "empty stack"; } }; -template -class threadsafe_stack -{ +template +class threadsafe_stack { private: - std::stack data; - mutable std::mutex m; + std::stack data; + mutable std::mutex m; + public: - threadsafe_stack(){} - threadsafe_stack(const threadsafe_stack& other) - { - std::lock_guard lock(other.m); - data=other.data; - } - threadsafe_stack& operator=(const threadsafe_stack&) = delete; + threadsafe_stack() {} + threadsafe_stack(const threadsafe_stack& other) + { + std::lock_guard lock(other.m); + data = other.data; + } + threadsafe_stack& operator=(const threadsafe_stack&) = delete; - void push(T new_value) - { - std::lock_guard lock(m); - data.push(std::move(new_value)); - } - std::shared_ptr pop() - { - std::lock_guard lock(m); - if(data.empty()) throw empty_stack(); - std::shared_ptr const res( - std::make_shared(std::move(data.top()))); - data.pop(); - return res; - } - void pop(T& value) - { - std::lock_guard lock(m); - if(data.empty()) throw empty_stack(); - value=std::move(data.top()); - data.pop(); - } - bool empty() const - { - std::lock_guard lock(m); - return data.empty(); - } + void push(T new_value) + { + std::lock_guard lock(m); + data.push(std::move(new_value)); + } + std::shared_ptr pop() + { + std::lock_guard lock(m); + if (data.empty()) + throw empty_stack(); + std::shared_ptr const res(std::make_shared(std::move(data.top()))); + data.pop(); + return res; + } + void pop(T& value) + { + std::lock_guard lock(m); + if (data.empty()) + throw empty_stack(); + value = std::move(data.top()); + data.pop(); + } + bool empty() const + { + std::lock_guard lock(m); + return data.empty(); + } }; - diff --git a/source/listing_6.10.cpp b/source/listing_6.10.cpp index 79f57f0..abf71be 100644 --- a/source/listing_6.10.cpp +++ b/source/listing_6.10.cpp @@ -1,44 +1,41 @@ -template -class threadsafe_queue -{ +template +class threadsafe_queue { private: - std::unique_ptr try_pop_head() - { - std::lock_guard head_lock(head_mutex); - if(head.get()==get_tail()) - { - return std::unique_ptr(); - } - return pop_head(); + std::unique_ptr try_pop_head() + { + std::lock_guard head_lock(head_mutex); + if (head.get() == get_tail()) { + return std::unique_ptr(); } + return pop_head(); + } - std::unique_ptr try_pop_head(T& value) - { - std::lock_guard head_lock(head_mutex); - if(head.get()==get_tail()) - { - return std::unique_ptr(); - } - value=std::move(*head->data); - return pop_head(); + std::unique_ptr try_pop_head(T& value) + { + std::lock_guard head_lock(head_mutex); + if (head.get() == get_tail()) { + return std::unique_ptr(); } + value = std::move(*head->data); + return pop_head(); + } public: - std::shared_ptr try_pop() - { - std::unique_ptr const old_head=try_pop_head(); - return old_head?old_head->data:std::shared_ptr(); - } + std::shared_ptr try_pop() + { + std::unique_ptr const old_head = try_pop_head(); + return old_head ? old_head->data : std::shared_ptr(); + } - bool try_pop(T& value) - { - std::unique_ptr const old_head=try_pop_head(value); - return old_head; - } + bool try_pop(T& value) + { + std::unique_ptr const old_head = try_pop_head(value); + return old_head; + } - void empty() - { - std::lock_guard head_lock(head_mutex); - return (head==get_tail()); - } + void empty() + { + std::lock_guard head_lock(head_mutex); + return (head == get_tail()); + } }; diff --git a/source/listing_6.11.cpp b/source/listing_6.11.cpp index ff1492a..67954e5 100644 --- a/source/listing_6.11.cpp +++ b/source/listing_6.11.cpp @@ -1,108 +1,97 @@ -#include -#include -#include +#include #include #include +#include +#include #include -#include +#include -template > -class threadsafe_lookup_table -{ +template > +class threadsafe_lookup_table { private: - class bucket_type + class bucket_type { + private: + typedef std::pair bucket_value; + typedef std::list bucket_data; + typedef typename bucket_data::iterator bucket_iterator; + + bucket_data data; + mutable boost::shared_mutex mutex; + + bucket_iterator find_entry_for(Key const& key) const { - private: - typedef std::pair bucket_value; - typedef std::list bucket_data; - typedef typename bucket_data::iterator bucket_iterator; - - bucket_data data; - mutable boost::shared_mutex mutex; - - bucket_iterator find_entry_for(Key const& key) const - { - return std::find_if(data.begin(),data.end(), - [&](bucket_value const& item) - {return item.first==key;}); - } - public: - Value value_for(Key const& key,Value const& default_value) const - { - boost::shared_lock lock(mutex); - bucket_iterator const found_entry=find_entry_for(key); - return (found_entry==data.end())? - default_value : found_entry->second; - } - - void add_or_update_mapping(Key const& key,Value const& value) - { - std::unique_lock lock(mutex); - bucket_iterator const found_entry=find_entry_for(key); - if(found_entry==data.end()) - { - data.push_back(bucket_value(key,value)); - } - else - { - found_entry->second=value; - } - } - - void remove_mapping(Key const& key) - { - std::unique_lock lock(mutex); - bucket_iterator const found_entry=find_entry_for(key); - if(found_entry!=data.end()) - { - data.erase(found_entry); - } - } - }; - - std::vector > buckets; - Hash hasher; - - bucket_type& get_bucket(Key const& key) const - { - std::size_t const bucket_index=hasher(key)%buckets.size(); - return *buckets[bucket_index]; + return std::find_if( + data.begin(), data.end(), [&](bucket_value const& item) { + return item.first == key; + }); } -public: - typedef Key key_type; - typedef Value mapped_type; - typedef Hash hash_type; - - threadsafe_lookup_table( - unsigned num_buckets=19, Hash const& hasher_=Hash()): - buckets(num_buckets),hasher(hasher_) + public: + Value value_for(Key const& key, Value const& default_value) const { - for(unsigned i=0;i lock(mutex); + bucket_iterator const found_entry = find_entry_for(key); + return (found_entry == data.end()) ? default_value : found_entry->second; } - threadsafe_lookup_table(threadsafe_lookup_table const& other)=delete; - threadsafe_lookup_table& operator=( - threadsafe_lookup_table const& other)=delete; - - Value value_for(Key const& key, - Value const& default_value=Value()) const + void add_or_update_mapping(Key const& key, Value const& value) { - return get_bucket(key).value_for(key,default_value); + std::unique_lock lock(mutex); + bucket_iterator const found_entry = find_entry_for(key); + if (found_entry == data.end()) { + data.push_back(bucket_value(key, value)); + } + else { + found_entry->second = value; + } } - - void add_or_update_mapping(Key const& key,Value const& value) - { - get_bucket(key).add_or_update_mapping(key,value); - } - + void remove_mapping(Key const& key) { - get_bucket(key).remove_mapping(key); + std::unique_lock lock(mutex); + bucket_iterator const found_entry = find_entry_for(key); + if (found_entry != data.end()) { + data.erase(found_entry); + } } + }; + + std::vector> buckets; + Hash hasher; + + bucket_type& get_bucket(Key const& key) const + { + std::size_t const bucket_index = hasher(key) % buckets.size(); + return *buckets[bucket_index]; + } + +public: + typedef Key key_type; + typedef Value mapped_type; + typedef Hash hash_type; + + threadsafe_lookup_table(unsigned num_buckets = 19, + Hash const& hasher_ = Hash()) + : buckets(num_buckets), hasher(hasher_) + { + for (unsigned i = 0; i < num_buckets; ++i) { + buckets[i].reset(new bucket_type); + } + } + + threadsafe_lookup_table(threadsafe_lookup_table const& other) = delete; + threadsafe_lookup_table& operator=(threadsafe_lookup_table const& other) = + delete; + + Value value_for(Key const& key, Value const& default_value = Value()) const + { + return get_bucket(key).value_for(key, default_value); + } + + void add_or_update_mapping(Key const& key, Value const& value) + { + get_bucket(key).add_or_update_mapping(key, value); + } + + void remove_mapping(Key const& key) { get_bucket(key).remove_mapping(key); } }; - - diff --git a/source/listing_6.12.cpp b/source/listing_6.12.cpp index 2e975a2..f23cc82 100644 --- a/source/listing_6.12.cpp +++ b/source/listing_6.12.cpp @@ -1,20 +1,17 @@ -std::map threadsafe_lookup_table::get_map() const +std::map +threadsafe_lookup_table::get_map() const { - std::vector > locks; - for(unsigned i=0;i(buckets[i].mutex)); + std::vector> locks; + for (unsigned i = 0; i < buckets.size(); ++i) { + locks.push_back(std::unique_lock(buckets[i].mutex)); + } + std::map res; + for (unsigned i = 0; i < buckets.size(); ++i) { + for (bucket_iterator it = buckets[i].data.begin(); + it != buckets[i].data.end(); + ++it) { + res.insert(*it); } - std::map res; - for(unsigned i=0;i #include -template -class threadsafe_list -{ - struct node - { - std::mutex m; - std::shared_ptr data; - std::unique_ptr next; +template +class threadsafe_list { + struct node { + std::mutex m; + std::shared_ptr data; + std::unique_ptr next; - node(): - next() - {} - - node(T const& value): - data(std::make_shared(value)) - {} - }; - - node head; + node() : next() {} + + node(T const& value) : data(std::make_shared(value)) {} + }; + + node head; public: - threadsafe_list() - {} + threadsafe_list() {} - ~threadsafe_list() - { - remove_if([](T const&){return true;}); - } + ~threadsafe_list() + { + remove_if([](T const&) { return true; }); + } - threadsafe_list(threadsafe_list const& other)=delete; - threadsafe_list& operator=(threadsafe_list const& other)=delete; - - void push_front(T const& value) - { - std::unique_ptr new_node(new node(value)); - std::lock_guard lk(head.m); - new_node->next=std::move(head.next); - head.next=std::move(new_node); - } + threadsafe_list(threadsafe_list const& other) = delete; + threadsafe_list& operator=(threadsafe_list const& other) = delete; - template - void for_each(Function f) - { - node* current=&head; - std::unique_lock lk(head.m); - while(node* const next=current->next.get()) - { - std::unique_lock next_lk(next->m); - lk.unlock(); - f(*next->data); - current=next; - lk=std::move(next_lk); - } - } + void push_front(T const& value) + { + std::unique_ptr new_node(new node(value)); + std::lock_guard lk(head.m); + new_node->next = std::move(head.next); + head.next = std::move(new_node); + } - template - std::shared_ptr find_first_if(Predicate p) - { - node* current=&head; - std::unique_lock lk(head.m); - while(node* const next=current->next.get()) - { - std::unique_lock next_lk(next->m); - lk.unlock(); - if(p(*next->data)) - { - return next->data; - } - current=next; - lk=std::move(next_lk); - } - return std::shared_ptr(); + template + void for_each(Function f) + { + node* current = &head; + std::unique_lock lk(head.m); + while (node* const next = current->next.get()) { + std::unique_lock next_lk(next->m); + lk.unlock(); + f(*next->data); + current = next; + lk = std::move(next_lk); } + } - template - void remove_if(Predicate p) - { - node* current=&head; - std::unique_lock lk(head.m); - while(node* const next=current->next.get()) - { - std::unique_lock next_lk(next->m); - if(p(*next->data)) - { - std::unique_ptr old_next=std::move(current->next); - current->next=std::move(next->next); - next_lk.unlock(); - } - else - { - lk.unlock(); - current=next; - lk=std::move(next_lk); - } - } + template + std::shared_ptr find_first_if(Predicate p) + { + node* current = &head; + std::unique_lock lk(head.m); + while (node* const next = current->next.get()) { + std::unique_lock next_lk(next->m); + lk.unlock(); + if (p(*next->data)) { + return next->data; + } + current = next; + lk = std::move(next_lk); } + return std::shared_ptr(); + } + + template + void remove_if(Predicate p) + { + node* current = &head; + std::unique_lock lk(head.m); + while (node* const next = current->next.get()) { + std::unique_lock next_lk(next->m); + if (p(*next->data)) { + std::unique_ptr old_next = std::move(current->next); + current->next = std::move(next->next); + next_lk.unlock(); + } + else { + lk.unlock(); + current = next; + lk = std::move(next_lk); + } + } + } }; - diff --git a/source/listing_6.2.cpp b/source/listing_6.2.cpp index c0aed9e..c9483e4 100644 --- a/source/listing_6.2.cpp +++ b/source/listing_6.2.cpp @@ -1,72 +1,70 @@ -#include -#include #include #include +#include +#include -template -class threadsafe_queue -{ +template +class threadsafe_queue { private: - mutable std::mutex mut; - std::queue data_queue; - std::condition_variable data_cond; + mutable std::mutex mut; + std::queue data_queue; + std::condition_variable data_cond; + public: - threadsafe_queue() - {} + threadsafe_queue() {} - void push(T new_value) - { - std::lock_guard lk(mut); - data_queue.push(std::move(new_value)); - data_cond.notify_one(); - } + void push(T new_value) + { + std::lock_guard lk(mut); + data_queue.push(std::move(new_value)); + data_cond.notify_one(); + } - void wait_and_pop(T& value) - { - std::unique_lock lk(mut); - data_cond.wait(lk,[this]{return !data_queue.empty();}); - value=std::move(data_queue.front()); - data_queue.pop(); - } + void wait_and_pop(T& value) + { + std::unique_lock lk(mut); + data_cond.wait(lk, [this] { return !data_queue.empty(); }); + value = std::move(data_queue.front()); + data_queue.pop(); + } - std::shared_ptr wait_and_pop() - { - std::unique_lock lk(mut); - data_cond.wait(lk,[this]{return !data_queue.empty();}); - std::shared_ptr res( - std::make_shared(std::move(data_queue.front()))); - data_queue.pop(); - return res; - } + std::shared_ptr wait_and_pop() + { + std::unique_lock lk(mut); + data_cond.wait(lk, [this] { return !data_queue.empty(); }); + std::shared_ptr res(std::make_shared(std::move(data_queue.front()))); + data_queue.pop(); + return res; + } - bool try_pop(T& value) - { - std::lock_guard lk(mut); - if(data_queue.empty()) - return false; - value=std::move(data_queue.front()); - data_queue.pop(); - } + bool try_pop(T& value) + { + std::lock_guard lk(mut); + if (data_queue.empty()) + return false; + value = std::move(data_queue.front()); + data_queue.pop(); + } - std::shared_ptr try_pop() - { - std::lock_guard lk(mut); - if(data_queue.empty()) - return std::shared_ptr(); - std::shared_ptr res( - std::make_shared(std::move(data_queue.front()))); - data_queue.pop(); - return res; - } + std::shared_ptr try_pop() + { + std::lock_guard lk(mut); + if (data_queue.empty()) + return std::shared_ptr(); + std::shared_ptr res(std::make_shared(std::move(data_queue.front()))); + data_queue.pop(); + return res; + } - bool empty() const - { - std::lock_guard lk(mut); - return data_queue.empty(); - } + bool empty() const + { + std::lock_guard lk(mut); + return data_queue.empty(); + } }; -int main() +int +main() { - threadsafe_queue rq; + threadsafe_queue rq; } diff --git a/source/listing_6.3.cpp b/source/listing_6.3.cpp index 35c0519..e32ed85 100644 --- a/source/listing_6.3.cpp +++ b/source/listing_6.3.cpp @@ -1,68 +1,65 @@ -#include -#include #include #include +#include +#include -template -class threadsafe_queue -{ +template +class threadsafe_queue { private: - mutable std::mutex mut; - std::queue > data_queue; - std::condition_variable data_cond; + mutable std::mutex mut; + std::queue> data_queue; + std::condition_variable data_cond; + public: - threadsafe_queue() - {} + threadsafe_queue() {} - void wait_and_pop(T& value) - { - std::unique_lock lk(mut); - data_cond.wait(lk,[this]{return !data_queue.empty();}); - value=std::move(*data_queue.front()); - data_queue.pop(); - } + void wait_and_pop(T& value) + { + std::unique_lock lk(mut); + data_cond.wait(lk, [this] { return !data_queue.empty(); }); + value = std::move(*data_queue.front()); + data_queue.pop(); + } - bool try_pop(T& value) - { - std::lock_guard lk(mut); - if(data_queue.empty()) - return false; - value=std::move(*data_queue.front()); - data_queue.pop(); - } + bool try_pop(T& value) + { + std::lock_guard lk(mut); + if (data_queue.empty()) + return false; + value = std::move(*data_queue.front()); + data_queue.pop(); + } - std::shared_ptr wait_and_pop() - { - std::unique_lock lk(mut); - data_cond.wait(lk,[this]{return !data_queue.empty();}); - std::shared_ptr res=data_queue.front(); - data_queue.pop(); - return res; - } + std::shared_ptr wait_and_pop() + { + std::unique_lock lk(mut); + data_cond.wait(lk, [this] { return !data_queue.empty(); }); + std::shared_ptr res = data_queue.front(); + data_queue.pop(); + return res; + } - std::shared_ptr try_pop() - { - std::lock_guard lk(mut); - if(data_queue.empty()) - return std::shared_ptr(); - std::shared_ptr res=data_queue.front(); - data_queue.pop(); - return res; - } + std::shared_ptr try_pop() + { + std::lock_guard lk(mut); + if (data_queue.empty()) + return std::shared_ptr(); + std::shared_ptr res = data_queue.front(); + data_queue.pop(); + return res; + } - bool empty() const - { - std::lock_guard lk(mut); - return data_queue.empty(); - } - - void push(T new_value) - { - std::shared_ptr data( - std::make_shared(std::move(new_value))); - std::lock_guard lk(mut); - data_queue.push(data); - data_cond.notify_one(); - } + bool empty() const + { + std::lock_guard lk(mut); + return data_queue.empty(); + } + void push(T new_value) + { + std::shared_ptr data(std::make_shared(std::move(new_value))); + std::lock_guard lk(mut); + data_queue.push(data); + data_cond.notify_one(); + } }; diff --git a/source/listing_6.4.cpp b/source/listing_6.4.cpp index 187b151..945d169 100644 --- a/source/listing_6.4.cpp +++ b/source/listing_6.4.cpp @@ -1,56 +1,45 @@ #include -template -class queue -{ +template +class queue { private: - struct node - { - T data; - std::unique_ptr next; + struct node { + T data; + std::unique_ptr next; + + node(T data_) : data(std::move(data_)) {} + }; + + std::unique_ptr head; + node* tail; - node(T data_): - data(std::move(data_)) - {} - }; - - std::unique_ptr head; - node* tail; - public: - queue(): - tail(nullptr) - {} + queue() : tail(nullptr) {} - queue(const queue& other)=delete; - queue& operator=(const queue& other)=delete; + queue(const queue& other) = delete; + queue& operator=(const queue& other) = delete; - std::shared_ptr try_pop() - { - if(!head) - { - return std::shared_ptr(); - } - std::shared_ptr const res( - std::make_shared(std::move(head->data))); - std::unique_ptr const old_head=std::move(head); - head=std::move(old_head->next); - return res; + std::shared_ptr try_pop() + { + if (!head) { + return std::shared_ptr(); } - - void push(T new_value) - { - std::unique_ptr p(new node(std::move(new_value))); - node* const new_tail=p.get(); - if(tail) - { - tail->next=std::move(p); - } - else - { - head=std::move(p); - } - tail=new_tail; + std::shared_ptr const res(std::make_shared(std::move(head->data))); + std::unique_ptr const old_head = std::move(head); + head = std::move(old_head->next); + return res; + } + + void push(T new_value) + { + std::unique_ptr p(new node(std::move(new_value))); + node* const new_tail = p.get(); + if (tail) { + tail->next = std::move(p); } + else { + head = std::move(p); + } + tail = new_tail; + } }; - diff --git a/source/listing_6.5.cpp b/source/listing_6.5.cpp index 661114b..383e442 100644 --- a/source/listing_6.5.cpp +++ b/source/listing_6.5.cpp @@ -1,46 +1,39 @@ #include -template -class queue -{ +template +class queue { private: - struct node - { - std::shared_ptr data; - std::unique_ptr next; - }; - - std::unique_ptr head; - node* tail; - + struct node { + std::shared_ptr data; + std::unique_ptr next; + }; + + std::unique_ptr head; + node* tail; + public: - queue(): - head(new node),tail(head.get()) - {} + queue() : head(new node), tail(head.get()) {} - queue(const queue& other)=delete; - queue& operator=(const queue& other)=delete; + queue(const queue& other) = delete; + queue& operator=(const queue& other) = delete; - std::shared_ptr try_pop() - { - if(head.get()==tail) - { - return std::shared_ptr(); - } - std::shared_ptr const res(head->data); - std::unique_ptr const old_head=std::move(head); - head=std::move(old_head->next); - return res; - } - - void push(T new_value) - { - std::shared_ptr new_data( - std::make_shared(std::move(new_value))); - std::unique_ptr p(new node); - tail->data=new_data; - node* const new_tail=p.get(); - tail->next=std::move(p); - tail=new_tail; + std::shared_ptr try_pop() + { + if (head.get() == tail) { + return std::shared_ptr(); } + std::shared_ptr const res(head->data); + std::unique_ptr const old_head = std::move(head); + head = std::move(old_head->next); + return res; + } + + void push(T new_value) + { + std::shared_ptr new_data(std::make_shared(std::move(new_value))); + std::unique_ptr p(new node); + tail->data = new_data; + node* const new_tail = p.get(); + tail->next = std::move(p); + tail = new_tail; + } }; - diff --git a/source/listing_6.6.cpp b/source/listing_6.6.cpp index 6a6eb54..62878f7 100644 --- a/source/listing_6.6.cpp +++ b/source/listing_6.6.cpp @@ -1,64 +1,56 @@ #include #include -template -class threadsafe_queue -{ +template +class threadsafe_queue { private: - struct node - { - std::shared_ptr data; - std::unique_ptr next; - }; - - std::mutex head_mutex; - std::unique_ptr head; - std::mutex tail_mutex; - node* tail; - - node* get_tail() - { - std::lock_guard tail_lock(tail_mutex); - return tail; - } + struct node { + std::shared_ptr data; + std::unique_ptr next; + }; - std::unique_ptr pop_head() - { - std::lock_guard head_lock(head_mutex); - if(head.get()==get_tail()) - { - return nullptr; - } - std::unique_ptr const old_head=std::move(head); - head=std::move(old_head->next); - return old_head; + std::mutex head_mutex; + std::unique_ptr head; + std::mutex tail_mutex; + node* tail; + + node* get_tail() + { + std::lock_guard tail_lock(tail_mutex); + return tail; + } + + std::unique_ptr pop_head() + { + std::lock_guard head_lock(head_mutex); + if (head.get() == get_tail()) { + return nullptr; } - + std::unique_ptr const old_head = std::move(head); + head = std::move(old_head->next); + return old_head; + } public: - threadsafe_queue(): - head(new node),tail(head.get()) - {} + threadsafe_queue() : head(new node), tail(head.get()) {} - threadsafe_queue(const threadsafe_queue& other)=delete; - threadsafe_queue& operator=(const threadsafe_queue& other)=delete; + threadsafe_queue(const threadsafe_queue& other) = delete; + threadsafe_queue& operator=(const threadsafe_queue& other) = delete; - std::shared_ptr try_pop() - { - std::unique_ptr old_head=pop_head(); - return old_head?old_head->data:std::shared_ptr(); - } - - void push(T new_value) - { - std::shared_ptr new_data( - std::make_shared(std::move(new_value))); - std::unique_ptr p(new node); - node* const new_tail=p.get(); - std::lock_guard tail_lock(tail_mutex); - tail->data=new_data; - tail->next=std::move(p); - tail=new_tail; - } + std::shared_ptr try_pop() + { + std::unique_ptr old_head = pop_head(); + return old_head ? old_head->data : std::shared_ptr(); + } + + void push(T new_value) + { + std::shared_ptr new_data(std::make_shared(std::move(new_value))); + std::unique_ptr p(new node); + node* const new_tail = p.get(); + std::lock_guard tail_lock(tail_mutex); + tail->data = new_data; + tail->next = std::move(p); + tail = new_tail; + } }; - diff --git a/source/listing_6.7.cpp b/source/listing_6.7.cpp index 7497a72..9c3103c 100644 --- a/source/listing_6.7.cpp +++ b/source/listing_6.7.cpp @@ -1,29 +1,26 @@ -template -class threadsafe_queue -{ +template +class threadsafe_queue { private: - struct node - { - std::shared_ptr data; - std::unique_ptr next; - }; - - std::mutex head_mutex; - std::unique_ptr head; - std::mutex tail_mutex; - node* tail; - std::condition_variable data_cond; -public: - threadsafe_queue(): - head(new node),tail(head.get()) - {} - threadsafe_queue(const threadsafe_queue& other)=delete; - threadsafe_queue& operator=(const threadsafe_queue& other)=delete; + struct node { + std::shared_ptr data; + std::unique_ptr next; + }; - std::shared_ptr try_pop(); - bool try_pop(T& value); - std::shared_ptr wait_and_pop(); - void wait_and_pop(T& value); - void push(T new_value); - void empty(); + std::mutex head_mutex; + std::unique_ptr head; + std::mutex tail_mutex; + node* tail; + std::condition_variable data_cond; + +public: + threadsafe_queue() : head(new node), tail(head.get()) {} + threadsafe_queue(const threadsafe_queue& other) = delete; + threadsafe_queue& operator=(const threadsafe_queue& other) = delete; + + std::shared_ptr try_pop(); + bool try_pop(T& value); + std::shared_ptr wait_and_pop(); + void wait_and_pop(T& value); + void push(T new_value); + void empty(); }; diff --git a/source/listing_6.8.cpp b/source/listing_6.8.cpp index c042254..a7dcc95 100644 --- a/source/listing_6.8.cpp +++ b/source/listing_6.8.cpp @@ -1,15 +1,15 @@ -template -void threadsafe_queue::push(T new_value) +template +void +threadsafe_queue::push(T new_value) { - std::shared_ptr new_data( - std::make_shared(std::move(new_value))); - std::unique_ptr p(new node); - { - std::lock_guard tail_lock(tail_mutex); - tail->data=new_data; - node* const new_tail=p.get(); - tail->next=std::move(p); - tail=new_tail; - } - data_cond.notify_one(); + std::shared_ptr new_data(std::make_shared(std::move(new_value))); + std::unique_ptr p(new node); + { + std::lock_guard tail_lock(tail_mutex); + tail->data = new_data; + node* const new_tail = p.get(); + tail->next = std::move(p); + tail = new_tail; + } + data_cond.notify_one(); } diff --git a/source/listing_6.9.cpp b/source/listing_6.9.cpp index d18a15e..5247ea5 100644 --- a/source/listing_6.9.cpp +++ b/source/listing_6.9.cpp @@ -1,49 +1,48 @@ -template -class threadsafe_queue -{ +template +class threadsafe_queue { private: - node* get_tail() - { - std::lock_guard tail_lock(tail_mutex); - return tail; - } + node* get_tail() + { + std::lock_guard tail_lock(tail_mutex); + return tail; + } - std::unique_ptr pop_head() - { - std::unique_ptr const old_head=std::move(head); - head=std::move(old_head->next); - return old_head; - } + std::unique_ptr pop_head() + { + std::unique_ptr const old_head = std::move(head); + head = std::move(old_head->next); + return old_head; + } - std::unique_lock wait_for_data() - { - std::unique_lock head_lock(head_mutex); - data_cond.wait(head_lock,[&]{return head!=get_tail();}); - return std::move(head_lock); - } + std::unique_lock wait_for_data() + { + std::unique_lock head_lock(head_mutex); + data_cond.wait(head_lock, [&] { return head != get_tail(); }); + return std::move(head_lock); + } - std::unique_ptr wait_pop_head() - { - std::unique_lock head_lock(wait_for_data()); - return pop_head(); - } + std::unique_ptr wait_pop_head() + { + std::unique_lock head_lock(wait_for_data()); + return pop_head(); + } + + std::unique_ptr wait_pop_head(T& value) + { + std::unique_lock head_lock(wait_for_data()); + value = std::move(*head->data); + return pop_head(); + } - std::unique_ptr wait_pop_head(T& value) - { - std::unique_lock head_lock(wait_for_data()); - value=std::move(*head->data); - return pop_head(); - } - public: - std::shared_ptr wait_and_pop() - { - std::unique_ptr const old_head=wait_pop_head(); - return old_head->data; - } + std::shared_ptr wait_and_pop() + { + std::unique_ptr const old_head = wait_pop_head(); + return old_head->data; + } - void wait_and_pop(T& value) - { - std::unique_ptr const old_head=wait_pop_head(value); - } + void wait_and_pop(T& value) + { + std::unique_ptr const old_head = wait_pop_head(value); + } }; diff --git a/source/listing_7.1.cpp b/source/listing_7.1.cpp index 8d141a8..c72e9c2 100644 --- a/source/listing_7.1.cpp +++ b/source/listing_7.1.cpp @@ -1,18 +1,14 @@ #include -class spinlock_mutex -{ - std::atomic_flag flag; +class spinlock_mutex { + std::atomic_flag flag; + public: - spinlock_mutex(): - flag(ATOMIC_FLAG_INIT) - {} - void lock() - { - while(flag.test_and_set(std::memory_order_acquire)); - } - void unlock() - { - flag.clear(std::memory_order_release); - } + spinlock_mutex() : flag(ATOMIC_FLAG_INIT) {} + void lock() + { + while (flag.test_and_set(std::memory_order_acquire)) + ; + } + void unlock() { flag.clear(std::memory_order_release); } }; diff --git a/source/listing_7.10.cpp b/source/listing_7.10.cpp index 3f05227..07a1f86 100644 --- a/source/listing_7.10.cpp +++ b/source/listing_7.10.cpp @@ -1,38 +1,37 @@ #include #include -template -class lock_free_stack -{ +template +class lock_free_stack { private: - struct node; - struct counted_node_ptr + struct node; + struct counted_node_ptr { + int external_count; + node* ptr; + }; + struct node { + std::shared_ptr data; + std::atomic internal_count; + counted_node_ptr next; + node(T const& data_) : data(std::make_shared(data_)), internal_count(0) { - int external_count; - node* ptr; - }; - struct node - { - std::shared_ptr data; - std::atomic internal_count; - counted_node_ptr next; - node(T const& data_): - data(std::make_shared(data_)), - internal_count(0) - {} - }; - std::atomic head; + } + }; + std::atomic head; + public: - ~lock_free_stack() - { - while(pop()); - } - void push(T const& data) - { - counted_node_ptr new_node; - new_node.ptr=new node(data); - new_node.external_count=1; - new_node.ptr->next=head.load(); - while(!head.compare_exchange_weak(new_node.ptr->next,new_node)); - } + ~lock_free_stack() + { + while (pop()) + ; + } + void push(T const& data) + { + counted_node_ptr new_node; + new_node.ptr = new node(data); + new_node.external_count = 1; + new_node.ptr->next = head.load(); + while (!head.compare_exchange_weak(new_node.ptr->next, new_node)) + ; + } }; diff --git a/source/listing_7.11.cpp b/source/listing_7.11.cpp index 72837d0..d7b96f1 100644 --- a/source/listing_7.11.cpp +++ b/source/listing_7.11.cpp @@ -1,46 +1,38 @@ -template -class lock_free_stack -{ +template +class lock_free_stack { private: - void increase_head_count(counted_node_ptr& old_counter) - { - counted_node_ptr new_counter; - do - { - new_counter=old_counter; - ++new_counter.external_count; - } - while(!head.compare_exchange_strong(old_counter,new_counter)); - old_counter.external_count=new_counter.external_count; - } + void increase_head_count(counted_node_ptr& old_counter) + { + counted_node_ptr new_counter; + do { + new_counter = old_counter; + ++new_counter.external_count; + } while (!head.compare_exchange_strong(old_counter, new_counter)); + old_counter.external_count = new_counter.external_count; + } + public: - std::shared_ptr pop() - { - counted_node_ptr old_head=head.load(); - for(;;) - { - increase_head_count(old_head); - node* const ptr=old_head.ptr; - if(!ptr) - { - return std::shared_ptr(); - } - if(head.compare_exchange_strong(old_head,ptr->next)) - { - std::shared_ptr res; - res.swap(ptr->data); - int const count_increase=old_head.external_count-2; - if(ptr->internal_count.fetch_add(count_increase)== - -count_increase) - { - delete ptr; - } - return res; - } - else if(ptr->internal_count.fetch_sub(1)==1) - { - delete ptr; - } + std::shared_ptr pop() + { + counted_node_ptr old_head = head.load(); + for (;;) { + increase_head_count(old_head); + node* const ptr = old_head.ptr; + if (!ptr) { + return std::shared_ptr(); + } + if (head.compare_exchange_strong(old_head, ptr->next)) { + std::shared_ptr res; + res.swap(ptr->data); + int const count_increase = old_head.external_count - 2; + if (ptr->internal_count.fetch_add(count_increase) == -count_increase) { + delete ptr; } + return res; + } + else if (ptr->internal_count.fetch_sub(1) == 1) { + delete ptr; + } } + } }; diff --git a/source/listing_7.12.cpp b/source/listing_7.12.cpp index 03756e5..a56bbc5 100644 --- a/source/listing_7.12.cpp +++ b/source/listing_7.12.cpp @@ -1,88 +1,78 @@ #include #include -template -class lock_free_stack -{ +template +class lock_free_stack { private: - struct node; - struct counted_node_ptr + struct node; + struct counted_node_ptr { + int external_count; + node* ptr; + }; + struct node { + std::shared_ptr data; + std::atomic internal_count; + counted_node_ptr next; + node(T const& data_) : data(std::make_shared(data_)), internal_count(0) { - int external_count; - node* ptr; - }; - struct node - { - std::shared_ptr data; - std::atomic internal_count; - counted_node_ptr next; - node(T const& data_): - data(std::make_shared(data_)), - internal_count(0) - {} - }; - std::atomic head; - void increase_head_count(counted_node_ptr& old_counter) - { - counted_node_ptr new_counter; - do - { - new_counter=old_counter; - ++new_counter.external_count; - } - while(!head.compare_exchange_strong( - old_counter,new_counter, - std::memory_order_acquire, - std::memory_order_relaxed)); - old_counter.external_count=new_counter.external_count; } + }; + std::atomic head; + void increase_head_count(counted_node_ptr& old_counter) + { + counted_node_ptr new_counter; + do { + new_counter = old_counter; + ++new_counter.external_count; + } while (!head.compare_exchange_strong(old_counter, + new_counter, + std::memory_order_acquire, + std::memory_order_relaxed)); + old_counter.external_count = new_counter.external_count; + } + public: - ~lock_free_stack() - { - while(pop()); - } - void push(T const& data) - { - counted_node_ptr new_node; - new_node.ptr=new node(data); - new_node.external_count=1; - new_node.ptr->next=head.load(std::memory_order_relaxed) - while(!head.compare_exchange_weak( - new_node.ptr->next,new_node, - std::memory_order_release, - std::memory_order_relaxed)); - } - std::shared_ptr pop() - { - counted_node_ptr old_head= - head.load(std::memory_order_relaxed); - for(;;) - { - increase_head_count(old_head); - node* const ptr=old_head.ptr; - if(!ptr) - { - return std::shared_ptr(); - } - if(head.compare_exchange_strong( - old_head,ptr->next,std::memory_order_relaxed)) - { - std::shared_ptr res; - res.swap(ptr->data); - int const count_increase=old_head.external_count-2; - if(ptr->internal_count.fetch_add( - count_increase,std::memory_order_release)==-count_increase) - { - delete ptr; - } - return res; - } - else if(ptr->internal_count.fetch_add( - -1,std::memory_order_relaxed)==1) - { - ptr->internal_count.load(std::memory_order_acquire); - delete ptr; - } + ~lock_free_stack() + { + while (pop()) + ; + } + void push(T const& data) + { + counted_node_ptr new_node; + new_node.ptr = new node(data); + new_node.external_count = 1; + new_node.ptr->next = head.load(std::memory_order_relaxed) while ( + !head.compare_exchange_weak(new_node.ptr->next, + new_node, + std::memory_order_release, + std::memory_order_relaxed)); + } + std::shared_ptr pop() + { + counted_node_ptr old_head = head.load(std::memory_order_relaxed); + for (;;) { + increase_head_count(old_head); + node* const ptr = old_head.ptr; + if (!ptr) { + return std::shared_ptr(); + } + if (head.compare_exchange_strong( + old_head, ptr->next, std::memory_order_relaxed)) { + std::shared_ptr res; + res.swap(ptr->data); + int const count_increase = old_head.external_count - 2; + if (ptr->internal_count.fetch_add( + count_increase, std::memory_order_release) == -count_increase) { + delete ptr; } + return res; + } + else if (ptr->internal_count.fetch_add(-1, std::memory_order_relaxed) == + 1) { + ptr->internal_count.load(std::memory_order_acquire); + delete ptr; + } } + } }; diff --git a/source/listing_7.13.cpp b/source/listing_7.13.cpp index f4a4f42..eb23292 100644 --- a/source/listing_7.13.cpp +++ b/source/listing_7.13.cpp @@ -1,62 +1,54 @@ -#include #include +#include -template -class lock_free_queue -{ +template +class lock_free_queue { private: - struct node - { - std::shared_ptr data; - node* next; - node(): - next(nullptr) - {} - }; - std::atomic head; - std::atomic tail; - node* pop_head() - { - node* const old_head=head.load(); - if(old_head==tail.load()) - { - return nullptr; - } - head.store(old_head->next); - return old_head; + struct node { + std::shared_ptr data; + node* next; + node() : next(nullptr) {} + }; + std::atomic head; + std::atomic tail; + node* pop_head() + { + node* const old_head = head.load(); + if (old_head == tail.load()) { + return nullptr; } + head.store(old_head->next); + return old_head; + } + public: - lock_free_queue(): - head(new node),tail(head.load()) - {} - lock_free_queue(const lock_free_queue& other)=delete; - lock_free_queue& operator=(const lock_free_queue& other)=delete; - ~lock_free_queue() - { - while(node* const old_head=head.load()) - { - head.store(old_head->next); - delete old_head; - } + lock_free_queue() : head(new node), tail(head.load()) {} + lock_free_queue(const lock_free_queue& other) = delete; + lock_free_queue& operator=(const lock_free_queue& other) = delete; + ~lock_free_queue() + { + while (node* const old_head = head.load()) { + head.store(old_head->next); + delete old_head; } - std::shared_ptr pop() - { - node* old_head=pop_head(); - if(!old_head) - { - return std::shared_ptr(); - } - std::shared_ptr const res(old_head->data); - delete old_head; - return res; - } - void push(T new_value) - { - std::shared_ptr new_data(std::make_shared(new_value)); - node* p=new node; - node* const old_tail=tail.load(); - old_tail->data.swap(new_data); - old_tail->next=p; - tail.store(p); + } + std::shared_ptr pop() + { + node* old_head = pop_head(); + if (!old_head) { + return std::shared_ptr(); } + std::shared_ptr const res(old_head->data); + delete old_head; + return res; + } + void push(T new_value) + { + std::shared_ptr new_data(std::make_shared(new_value)); + node* p = new node; + node* const old_tail = tail.load(); + old_tail->data.swap(new_data); + old_tail->next = p; + tail.store(p); + } }; diff --git a/source/listing_7.14.cpp b/source/listing_7.14.cpp index 0aced25..bca43b6 100644 --- a/source/listing_7.14.cpp +++ b/source/listing_7.14.cpp @@ -1,20 +1,18 @@ -void push(T new_value) +void +push(T new_value) { - std::unique_ptr new_data(new T(new_value)); - counted_node_ptr new_next; - new_next.ptr=new node; - new_next.external_count=1; - for(;;) - { - node* const old_tail=tail.load(); - T* old_data=nullptr; - if(old_tail->data.compare_exchange_strong( - old_data,new_data.get())) - { - old_tail->next=new_next; - tail.store(new_next.ptr); - new_data.release(); - break; - } + std::unique_ptr new_data(new T(new_value)); + counted_node_ptr new_next; + new_next.ptr = new node; + new_next.external_count = 1; + for (;;) { + node* const old_tail = tail.load(); + T* old_data = nullptr; + if (old_tail->data.compare_exchange_strong(old_data, new_data.get())) { + old_tail->next = new_next; + tail.store(new_next.ptr); + new_data.release(); + break; } + } } diff --git a/source/listing_7.15.cpp b/source/listing_7.15.cpp index 2342ad3..915151b 100644 --- a/source/listing_7.15.cpp +++ b/source/listing_7.15.cpp @@ -1,59 +1,54 @@ #include -template -class lock_free_queue -{ +template +class lock_free_queue { private: - struct node; - struct counted_node_ptr + struct node; + struct counted_node_ptr { + int external_count; + node* ptr; + }; + std::atomic head; + std::atomic tail; + struct node_counter { + unsigned internal_count : 30; + unsigned external_counters : 2; + }; + struct node { + std::atomic data; + std::atomic count; + counted_node_ptr next; + node() { - int external_count; - node* ptr; - }; - std::atomic head; - std::atomic tail; - struct node_counter - { - unsigned internal_count:30; - unsigned external_counters:2; - }; - struct node - { - std::atomic data; - std::atomic count; - counted_node_ptr next; - node() - { - node_counter new_count; - new_count.internal_count=0; - new_count.external_counters=2; - count.store(new_count); - next.ptr=nullptr; - next.external_count=0; - } - }; -public: - void push(T new_value) - { - std::unique_ptr new_data(new T(new_value)); - counted_node_ptr new_next; - new_next.ptr=new node; - new_next.external_count=1; - counted_node_ptr old_tail=tail.load(); - for(;;) - { - increase_external_count(tail,old_tail); - T* old_data=nullptr; - if(old_tail.ptr->data.compare_exchange_strong( - old_data,new_data.get())) - { - old_tail.ptr->next=new_next; - old_tail=tail.exchange(new_next); - free_external_counter(old_tail); - new_data.release(); - break; - } - old_tail.ptr->release_ref(); - } + node_counter new_count; + new_count.internal_count = 0; + new_count.external_counters = 2; + count.store(new_count); + next.ptr = nullptr; + next.external_count = 0; } + }; + +public: + void push(T new_value) + { + std::unique_ptr new_data(new T(new_value)); + counted_node_ptr new_next; + new_next.ptr = new node; + new_next.external_count = 1; + counted_node_ptr old_tail = tail.load(); + for (;;) { + increase_external_count(tail, old_tail); + T* old_data = nullptr; + if (old_tail.ptr->data.compare_exchange_strong(old_data, + new_data.get())) { + old_tail.ptr->next = new_next; + old_tail = tail.exchange(new_next); + free_external_counter(old_tail); + new_data.release(); + break; + } + old_tail.ptr->release_ref(); + } + } }; diff --git a/source/listing_7.16.cpp b/source/listing_7.16.cpp index a3d74bc..d97fe44 100644 --- a/source/listing_7.16.cpp +++ b/source/listing_7.16.cpp @@ -1,31 +1,27 @@ -template -class lock_free_queue -{ +template +class lock_free_queue { private: - struct node - { - void release_ref(); - }; + struct node { + void release_ref(); + }; + public: - std::unique_ptr pop() - { - counted_node_ptr old_head=head.load(std::memory_order_relaxed); - for(;;) - { - increase_external_count(head,old_head); - node* const ptr=old_head.ptr; - if(ptr==tail.load().ptr) - { - ptr->release_ref(); - return std::unique_ptr(); - } - if(head.compare_exchange_strong(old_head,ptr->next)) - { - T* const res=ptr->data.exchange(nullptr); - free_external_counter(old_head); - return std::unique_ptr(res); - } - ptr->release_ref(); - } + std::unique_ptr pop() + { + counted_node_ptr old_head = head.load(std::memory_order_relaxed); + for (;;) { + increase_external_count(head, old_head); + node* const ptr = old_head.ptr; + if (ptr == tail.load().ptr) { + ptr->release_ref(); + return std::unique_ptr(); + } + if (head.compare_exchange_strong(old_head, ptr->next)) { + T* const res = ptr->data.exchange(nullptr); + free_external_counter(old_head); + return std::unique_ptr(res); + } + ptr->release_ref(); } + } }; diff --git a/source/listing_7.17.cpp b/source/listing_7.17.cpp index 3262a51..6eb4c4f 100644 --- a/source/listing_7.17.cpp +++ b/source/listing_7.17.cpp @@ -1,27 +1,21 @@ -template -class lock_free_queue -{ +template +class lock_free_queue { private: - struct node + struct node { + void release_ref() { - void release_ref() - { - node_counter old_counter= - count.load(std::memory_order_relaxed); - node_counter new_counter; - do - { - new_counter=old_counter; - --new_counter.internal_count; - } - while(!count.compare_exchange_strong( - old_counter,new_counter, - std::memory_order_acquire,std::memory_order_relaxed)); - if(!new_counter.internal_count && - !new_counter.external_counters) - { - delete this; - } - } - }; + node_counter old_counter = count.load(std::memory_order_relaxed); + node_counter new_counter; + do { + new_counter = old_counter; + --new_counter.internal_count; + } while (!count.compare_exchange_strong(old_counter, + new_counter, + std::memory_order_acquire, + std::memory_order_relaxed)); + if (!new_counter.internal_count && !new_counter.external_counters) { + delete this; + } + } + }; }; diff --git a/source/listing_7.18.cpp b/source/listing_7.18.cpp index 60f2291..83bf9aa 100644 --- a/source/listing_7.18.cpp +++ b/source/listing_7.18.cpp @@ -1,20 +1,17 @@ -template -class lock_free_queue -{ +template +class lock_free_queue { private: - static void increase_external_count( - std::atomic& counter, - counted_node_ptr& old_counter) - { - counted_node_ptr new_counter; - do - { - new_counter=old_counter; - ++new_counter.external_count; - } - while(!counter.compare_exchange_strong( - old_counter,new_counter, - std::memory_order_acquire,std::memory_order_relaxed)); - old_counter.external_count=new_counter.external_count; - } + static void increase_external_count(std::atomic& counter, + counted_node_ptr& old_counter) + { + counted_node_ptr new_counter; + do { + new_counter = old_counter; + ++new_counter.external_count; + } while (!counter.compare_exchange_strong(old_counter, + new_counter, + std::memory_order_acquire, + std::memory_order_relaxed)); + old_counter.external_count = new_counter.external_count; + } }; diff --git a/source/listing_7.19.cpp b/source/listing_7.19.cpp index 0667b55..6c9bd1d 100644 --- a/source/listing_7.19.cpp +++ b/source/listing_7.19.cpp @@ -1,27 +1,22 @@ -template -class lock_free_queue -{ +template +class lock_free_queue { private: - static void free_external_counter(counted_node_ptr &old_node_ptr) - { - node* const ptr=old_node_ptr.ptr; - int const count_increase=old_node_ptr.external_count-2; - node_counter old_counter= - ptr->count.load(std::memory_order_relaxed); - node_counter new_counter; - do - { - new_counter=old_counter; - --new_counter.external_counters; - new_counter.internal_count+=count_increase; - } - while(!ptr->count.compare_exchange_strong( - old_counter,new_counter, - std::memory_order_acquire,std::memory_order_relaxed)); - if(!new_counter.internal_count && - !new_counter.external_counters) - { - delete ptr; - } + static void free_external_counter(counted_node_ptr& old_node_ptr) + { + node* const ptr = old_node_ptr.ptr; + int const count_increase = old_node_ptr.external_count - 2; + node_counter old_counter = ptr->count.load(std::memory_order_relaxed); + node_counter new_counter; + do { + new_counter = old_counter; + --new_counter.external_counters; + new_counter.internal_count += count_increase; + } while (!ptr->count.compare_exchange_strong(old_counter, + new_counter, + std::memory_order_acquire, + std::memory_order_relaxed)); + if (!new_counter.internal_count && !new_counter.external_counters) { + delete ptr; } + } }; diff --git a/source/listing_7.2.cpp b/source/listing_7.2.cpp index f16271c..903cb17 100644 --- a/source/listing_7.2.cpp +++ b/source/listing_7.2.cpp @@ -1,23 +1,21 @@ #include -template -class lock_free_stack -{ +template +class lock_free_stack { private: - struct node - { - T data; - node* next; - node(T const& data_): - data(data_) - {} - }; - std::atomic head; + struct node { + T data; + node* next; + node(T const& data_) : data(data_) {} + }; + std::atomic head; + public: - void push(T const& data) - { - node* const new_node=new node(data); - new_node->next=head.load(); - while(!head.compare_exchange_weak(new_node->next,new_node)); - } + void push(T const& data) + { + node* const new_node = new node(data); + new_node->next = head.load(); + while (!head.compare_exchange_weak(new_node->next, new_node)) + ; + } }; diff --git a/source/listing_7.20.cpp b/source/listing_7.20.cpp index c7de500..d3a5819 100644 --- a/source/listing_7.20.cpp +++ b/source/listing_7.20.cpp @@ -1,33 +1,29 @@ -template -class lock_free_queue -{ +template +class lock_free_queue { private: - struct node - { - std::atomic data; - std::atomic count; - std::atomic next; - }; + struct node { + std::atomic data; + std::atomic count; + std::atomic next; + }; + public: - std::unique_ptr pop() - { - counted_node_ptr old_head=head.load(std::memory_order_relaxed); - for(;;) - { - increase_external_count(head,old_head); - node* const ptr=old_head.ptr; - if(ptr==tail.load().ptr) - { - return std::unique_ptr(); - } - counted_node_ptr next=ptr->next.load(); - if(head.compare_exchange_strong(old_head,next)) - { - T* const res=ptr->data.exchange(nullptr); - free_external_counter(old_head); - return std::unique_ptr(res); - } - ptr->release_ref(); - } + std::unique_ptr pop() + { + counted_node_ptr old_head = head.load(std::memory_order_relaxed); + for (;;) { + increase_external_count(head, old_head); + node* const ptr = old_head.ptr; + if (ptr == tail.load().ptr) { + return std::unique_ptr(); + } + counted_node_ptr next = ptr->next.load(); + if (head.compare_exchange_strong(old_head, next)) { + T* const res = ptr->data.exchange(nullptr); + free_external_counter(old_head); + return std::unique_ptr(res); + } + ptr->release_ref(); } + } }; diff --git a/source/listing_7.21.cpp b/source/listing_7.21.cpp index c13bca1..1f66f47 100644 --- a/source/listing_7.21.cpp +++ b/source/listing_7.21.cpp @@ -1,55 +1,49 @@ -template -class lock_free_queue -{ +template +class lock_free_queue { private: - void set_new_tail(counted_node_ptr &old_tail, - counted_node_ptr const &new_tail) - { - node* const current_tail_ptr=old_tail.ptr; - while(!tail.compare_exchange_weak(old_tail,new_tail) && - old_tail.ptr==current_tail_ptr); - if(old_tail.ptr==current_tail_ptr) - free_external_counter(old_tail); - else - current_tail_ptr->release_ref(); - } + void set_new_tail(counted_node_ptr& old_tail, + counted_node_ptr const& new_tail) + { + node* const current_tail_ptr = old_tail.ptr; + while (!tail.compare_exchange_weak(old_tail, new_tail) && + old_tail.ptr == current_tail_ptr) + ; + if (old_tail.ptr == current_tail_ptr) + free_external_counter(old_tail); + else + current_tail_ptr->release_ref(); + } + public: - void push(T new_value) - { - std::unique_ptr new_data(new T(new_value)); - counted_node_ptr new_next; - new_next.ptr=new node; - new_next.external_count=1; - counted_node_ptr old_tail=tail.load(); - for(;;) - { - increase_external_count(tail,old_tail); - T* old_data=nullptr; - if(old_tail.ptr->data.compare_exchange_strong( - old_data,new_data.get())) - { - counted_node_ptr old_next={0}; - if(!old_tail.ptr->next.compare_exchange_strong( - old_next,new_next)) - { - delete new_next.ptr; - new_next=old_next; - } - set_new_tail(old_tail, new_next); - new_data.release(); - break; - } - else - { - counted_node_ptr old_next={0}; - if(old_tail.ptr->next.compare_exchange_strong( - old_next,new_next)) - { - old_next=new_next; - new_next.ptr=new node; - } - set_new_tail(old_tail, old_next); - } + void push(T new_value) + { + std::unique_ptr new_data(new T(new_value)); + counted_node_ptr new_next; + new_next.ptr = new node; + new_next.external_count = 1; + counted_node_ptr old_tail = tail.load(); + for (;;) { + increase_external_count(tail, old_tail); + T* old_data = nullptr; + if (old_tail.ptr->data.compare_exchange_strong(old_data, + new_data.get())) { + counted_node_ptr old_next = {0}; + if (!old_tail.ptr->next.compare_exchange_strong(old_next, new_next)) { + delete new_next.ptr; + new_next = old_next; } + set_new_tail(old_tail, new_next); + new_data.release(); + break; + } + else { + counted_node_ptr old_next = {0}; + if (old_tail.ptr->next.compare_exchange_strong(old_next, new_next)) { + old_next = new_next; + new_next.ptr = new node; + } + set_new_tail(old_tail, old_next); + } } + } }; diff --git a/source/listing_7.3.cpp b/source/listing_7.3.cpp index 7568466..c687631 100644 --- a/source/listing_7.3.cpp +++ b/source/listing_7.3.cpp @@ -1,31 +1,29 @@ #include #include -template -class lock_free_stack -{ +template +class lock_free_stack { private: - struct node - { - std::shared_ptr data; - node* next; - node(T const& data_): - data(std::make_shared(data_)) - {} - }; - std::atomic head; + struct node { + std::shared_ptr data; + node* next; + node(T const& data_) : data(std::make_shared(data_)) {} + }; + std::atomic head; + public: - void push(T const& data) - { - node* const new_node=new node(data); - new_node->next=head.load(); - while(!head.compare_exchange_weak(new_node->next,new_node)); - } - std::shared_ptr pop() - { - node* old_head=head.load(); - while(old_head && - !head.compare_exchange_weak(old_head,old_head->next)); - return old_head ? old_head->data : std::shared_ptr(); - } + void push(T const& data) + { + node* const new_node = new node(data); + new_node->next = head.load(); + while (!head.compare_exchange_weak(new_node->next, new_node)) + ; + } + std::shared_ptr pop() + { + node* old_head = head.load(); + while (old_head && !head.compare_exchange_weak(old_head, old_head->next)) + ; + return old_head ? old_head->data : std::shared_ptr(); + } }; diff --git a/source/listing_7.4.cpp b/source/listing_7.4.cpp index c5cf97c..e032a96 100644 --- a/source/listing_7.4.cpp +++ b/source/listing_7.4.cpp @@ -1,25 +1,24 @@ #include #include -template -class lock_free_stack -{ +template +class lock_free_stack { private: - std::atomic threads_in_pop; - void try_reclaim(node* old_head); + std::atomic threads_in_pop; + void try_reclaim(node* old_head); + public: - std::shared_ptr pop() - { - ++threads_in_pop; - node* old_head=head.load(); - while(old_head && - !head.compare_exchange_weak(old_head,old_head->next)); - std::shared_ptr res; - if(old_head) - { - res.swap(old_head->data); - } - try_reclaim(old_head); - return res; + std::shared_ptr pop() + { + ++threads_in_pop; + node* old_head = head.load(); + while (old_head && !head.compare_exchange_weak(old_head, old_head->next)) + ; + std::shared_ptr res; + if (old_head) { + res.swap(old_head->data); } + try_reclaim(old_head); + return res; + } }; diff --git a/source/listing_7.5.cpp b/source/listing_7.5.cpp index 34d6ff6..5c4889d 100644 --- a/source/listing_7.5.cpp +++ b/source/listing_7.5.cpp @@ -1,57 +1,47 @@ #include -template -class lock_free_stack -{ +template +class lock_free_stack { private: - std::atomic to_be_deleted; - static void delete_nodes(node* nodes) - { - while(nodes) - { - node* next=nodes->next; - delete nodes; - nodes=next; - } + std::atomic to_be_deleted; + static void delete_nodes(node* nodes) + { + while (nodes) { + node* next = nodes->next; + delete nodes; + nodes = next; } - void try_reclaim(node* old_head) - { - if(threads_in_pop==1) - { - node* nodes_to_delete=to_be_deleted.exchange(nullptr); - if(!--threads_in_pop) - { - delete_nodes(nodes_to_delete); - } - else if(nodes_to_delete) - { - chain_pending_nodes(nodes_to_delete); - } - delete old_head; - } - else - { - chain_pending_node(old_head); - --threads_in_pop; - } + } + void try_reclaim(node* old_head) + { + if (threads_in_pop == 1) { + node* nodes_to_delete = to_be_deleted.exchange(nullptr); + if (!--threads_in_pop) { + delete_nodes(nodes_to_delete); + } + else if (nodes_to_delete) { + chain_pending_nodes(nodes_to_delete); + } + delete old_head; } - void chain_pending_nodes(node* nodes) - { - node* last=nodes; - while(node* const next=last->next) - { - last=next; - } - chain_pending_nodes(nodes,last); + else { + chain_pending_node(old_head); + --threads_in_pop; } - void chain_pending_nodes(node* first,node* last) - { - last->next=to_be_deleted; - while(!to_be_deleted.compare_exchange_weak( - last->next,first)); - } - void chain_pending_node(node* n) - { - chain_pending_nodes(n,n); + } + void chain_pending_nodes(node* nodes) + { + node* last = nodes; + while (node* const next = last->next) { + last = next; } + chain_pending_nodes(nodes, last); + } + void chain_pending_nodes(node* first, node* last) + { + last->next = to_be_deleted; + while (!to_be_deleted.compare_exchange_weak(last->next, first)) + ; + } + void chain_pending_node(node* n) { chain_pending_nodes(n, n); } }; diff --git a/source/listing_7.6.cpp b/source/listing_7.6.cpp index 3a2606b..c8db1dc 100644 --- a/source/listing_7.6.cpp +++ b/source/listing_7.6.cpp @@ -1,36 +1,30 @@ #include #include -std::shared_ptr pop() +std::shared_ptr +pop() { - std::atomic& hp=get_hazard_pointer_for_current_thread(); - node* old_head=head.load(); - do - { - node* temp; - do - { - temp=old_head; - hp.store(old_head); - old_head=head.load(); - } while(old_head!=temp); + std::atomic& hp = get_hazard_pointer_for_current_thread(); + node* old_head = head.load(); + do { + node* temp; + do { + temp = old_head; + hp.store(old_head); + old_head = head.load(); + } while (old_head != temp); + } while (old_head && !head.compare_exchange_strong(old_head, old_head->next)); + hp.store(nullptr); + std::shared_ptr res; + if (old_head) { + res.swap(old_head->data); + if (outstanding_hazard_pointers_for(old_head)) { + reclaim_later(old_head); } - while(old_head && - !head.compare_exchange_strong(old_head,old_head->next)); - hp.store(nullptr); - std::shared_ptr res; - if(old_head) - { - res.swap(old_head->data); - if(outstanding_hazard_pointers_for(old_head)) - { - reclaim_later(old_head); - } - else - { - delete old_head; - } - delete_nodes_with_no_hazards(); + else { + delete old_head; } - return res; + delete_nodes_with_no_hazards(); + } + return res; } diff --git a/source/listing_7.7.cpp b/source/listing_7.7.cpp index 70603c8..fe01531 100644 --- a/source/listing_7.7.cpp +++ b/source/listing_7.7.cpp @@ -1,49 +1,42 @@ #include #include -unsigned const max_hazard_pointers=100; -struct hazard_pointer -{ - std::atomic id; - std::atomic pointer; +unsigned const max_hazard_pointers = 100; +struct hazard_pointer { + std::atomic id; + std::atomic pointer; }; hazard_pointer hazard_pointers[max_hazard_pointers]; -class hp_owner -{ - hazard_pointer* hp; +class hp_owner { + hazard_pointer* hp; + public: - hp_owner(hp_owner const&)=delete; - hp_owner operator=(hp_owner const&)=delete; - hp_owner(): - hp(nullptr) - { - for(unsigned i=0;i& get_pointer() - { - return hp->pointer; - } - ~hp_owner() - { - hp->pointer.store(nullptr); - hp->id.store(std::thread::id()); + if (!hp) { + throw std::runtime_error("No hazard pointers available"); } + } + std::atomic& get_pointer() { return hp->pointer; } + ~hp_owner() + { + hp->pointer.store(nullptr); + hp->id.store(std::thread::id()); + } }; -std::atomic& get_hazard_pointer_for_current_thread() +std::atomic& +get_hazard_pointer_for_current_thread() { - thread_local static hp_owner hazard; - return hazard.get_pointer(); + thread_local static hp_owner hazard; + return hazard.get_pointer(); } diff --git a/source/listing_7.8.cpp b/source/listing_7.8.cpp index f7ba86c..55e2653 100644 --- a/source/listing_7.8.cpp +++ b/source/listing_7.8.cpp @@ -1,51 +1,47 @@ #include -template -void do_delete(void* p) +template +void +do_delete(void* p) { - delete static_cast(p); + delete static_cast(p); } -struct data_to_reclaim -{ - void* data; - std::function deleter; - data_to_reclaim* next; - template - data_to_reclaim(T* p): - data(p), - deleter(&do_delete), - next(0) - {} - ~data_to_reclaim() - { - deleter(data); - } +struct data_to_reclaim { + void* data; + std::function deleter; + data_to_reclaim* next; + template + data_to_reclaim(T* p) : data(p), deleter(&do_delete), next(0) + { + } + ~data_to_reclaim() { deleter(data); } }; std::atomic nodes_to_reclaim; -void add_to_reclaim_list(data_to_reclaim* node) +void +add_to_reclaim_list(data_to_reclaim* node) { - node->next=nodes_to_reclaim.load(); - while(!nodes_to_reclaim.compare_exchange_weak(node->next,node)); + node->next = nodes_to_reclaim.load(); + while (!nodes_to_reclaim.compare_exchange_weak(node->next, node)) + ; } -template -void reclaim_later(T* data) +template +void +reclaim_later(T* data) { - add_to_reclaim_list(new data_to_reclaim(data)); + add_to_reclaim_list(new data_to_reclaim(data)); } -void delete_nodes_with_no_hazards() +void +delete_nodes_with_no_hazards() { - data_to_reclaim* current=nodes_to_reclaim.exchange(nullptr); - while(current) - { - data_to_reclaim* const next=current->next; - if(!outstanding_hazard_pointers_for(current->data)) - { - delete current; - } - else - { - add_to_reclaim_list(current); - } - current=next; + data_to_reclaim* current = nodes_to_reclaim.exchange(nullptr); + while (current) { + data_to_reclaim* const next = current->next; + if (!outstanding_hazard_pointers_for(current->data)) { + delete current; } + else { + add_to_reclaim_list(current); + } + current = next; + } } diff --git a/source/listing_7.9.cpp b/source/listing_7.9.cpp index d3c09b7..3de9601 100644 --- a/source/listing_7.9.cpp +++ b/source/listing_7.9.cpp @@ -1,32 +1,30 @@ #include #include -template -class lock_free_stack -{ +template +class lock_free_stack { private: - struct node - { - std::shared_ptr data; - std::shared_ptr next; - node(T const& data_): - data(std::make_shared(data_)) - {} - }; - std::shared_ptr head; + struct node { + std::shared_ptr data; + std::shared_ptr next; + node(T const& data_) : data(std::make_shared(data_)) {} + }; + std::shared_ptr head; + public: - void push(T const& data) - { - std::shared_ptr const new_node=std::make_shared(data); - new_node->next=head.load(); - while(!std::atomic_compare_exchange_weak( - &head,&new_node->next,new_node)); - } - std::shared_ptr pop() - { - std::shared_ptr old_head=std::atomic_load(&head); - while(old_head && !std::atomic_compare_exchange_weak( - &head,&old_head,old_head->next)); - return old_head ? old_head->data : std::shared_ptr(); - } + void push(T const& data) + { + std::shared_ptr const new_node = std::make_shared(data); + new_node->next = head.load(); + while (!std::atomic_compare_exchange_weak(&head, &new_node->next, new_node)) + ; + } + std::shared_ptr pop() + { + std::shared_ptr old_head = std::atomic_load(&head); + while (old_head && + !std::atomic_compare_exchange_weak(&head, &old_head, old_head->next)) + ; + return old_head ? old_head->data : std::shared_ptr(); + } }; diff --git a/source/listing_8.1.cpp b/source/listing_8.1.cpp index e345302..fed3c9c 100644 --- a/source/listing_8.1.cpp +++ b/source/listing_8.1.cpp @@ -1,102 +1,96 @@ -template -struct sorter -{ - struct chunk_to_sort - { - std::list data; - std::promise > promise; - }; +template +struct sorter { + struct chunk_to_sort { + std::list data; + std::promise> promise; + }; - thread_safe_stack chunks; - std::vector threads; - unsigned const max_thread_count; - std::atomic end_of_data; + thread_safe_stack chunks; + std::vector threads; + unsigned const max_thread_count; + std::atomic end_of_data; - sorter(): - max_thread_count(std::thread::hardware_concurrency()-1), + sorter() + : max_thread_count(std::thread::hardware_concurrency() - 1), end_of_data(false) - {} + { + } - ~sorter() - { - end_of_data=true; - for(unsigned i=0;i chunk = chunks.pop(); + if (chunk) { + sort_chunk(chunk); + } + } + + std::list do_sort(std::list& chunk_data) + { + if (chunk_data.empty()) { + return chunk_data; } - void try_sort_chunk() - { - boost::shared_ptr chunk=chunks.pop(); - if(chunk) - { - sort_chunk(chunk); - } + std::list result; + result.splice(result.begin(), chunk_data, chunk_data.begin()); + T const& partition_val = *result.begin(); + + typename std::list::iterator divide_point = + std::partition(chunk_data.begin(), chunk_data.end(), [&](T const& val) { + return val < partition_val; + }); + chunk_to_sort new_lower_chunk; + new_lower_chunk.data.splice(new_lower_chunk.data.end(), + chunk_data, + chunk_data.begin(), + divide_point); + + std::future> new_lower = new_lower_chunk.promise.get_future(); + chunks.push(std::move(new_lower_chunk)); + if (threads.size() < max_thread_count) { + threads.push_back(std::thread(&sorter::sort_thread, this)); } - std::list do_sort(std::list& chunk_data) - { - if(chunk_data.empty()) - { - return chunk_data; - } + std::list new_higher(do_sort(chunk_data)); - std::list result; - result.splice(result.begin(),chunk_data,chunk_data.begin()); - T const& partition_val=*result.begin(); - - typename std::list::iterator divide_point= - std::partition(chunk_data.begin(),chunk_data.end(), - [&](T const& val){return val > new_lower= - new_lower_chunk.promise.get_future(); - chunks.push(std::move(new_lower_chunk)); - if(threads.size()::sort_thread,this)); - } - - std::list new_higher(do_sort(chunk_data)); - - result.splice(result.end(),new_higher); - while(new_lower.wait_for(std::chrono::seconds(0)) != - std::future_status::ready) - { - try_sort_chunk(); - } - - result.splice(result.begin(),new_lower.get()); - return result; + result.splice(result.end(), new_higher); + while (new_lower.wait_for(std::chrono::seconds(0)) != + std::future_status::ready) { + try_sort_chunk(); } - void sort_chunk(boost::shared_ptr const& chunk) - { - chunk->promise.set_value(do_sort(chunk->data)); - } + result.splice(result.begin(), new_lower.get()); + return result; + } - void sort_thread() - { - while(!end_of_data) - { - try_sort_chunk(); - std::this_thread::yield(); - } + void sort_chunk(boost::shared_ptr const& chunk) + { + chunk->promise.set_value(do_sort(chunk->data)); + } + + void sort_thread() + { + while (!end_of_data) { + try_sort_chunk(); + std::this_thread::yield(); } + } }; -template -std::list parallel_quick_sort(std::list input) +template +std::list +parallel_quick_sort(std::list input) { - if(input.empty()) - { - return input; - } - sorter s; - return s.do_sort(input); + if (input.empty()) { + return input; + } + sorter s; + return s.do_sort(input); } diff --git a/source/listing_8.10.cpp b/source/listing_8.10.cpp index 07241ea..63fe43a 100644 --- a/source/listing_8.10.cpp +++ b/source/listing_8.10.cpp @@ -1,45 +1,45 @@ -template -Iterator parallel_find_impl(Iterator first,Iterator last,MatchType match, - std::atomic& done) +template +Iterator +parallel_find_impl(Iterator first, + Iterator last, + MatchType match, + std::atomic& done) { - try - { - unsigned long const length=std::distance(first,last); - unsigned long const min_per_thread=25; - if(length<(2*min_per_thread)) - { - for(;(first!=last) && !done.load();++first) - { - if(*first==match) - { - done=true; - return first; - } - } - return last; - } - else - { - Iterator const mid_point=first+(length/2); - std::future async_result= - std::async(¶llel_find_impl, - mid_point,last,match,std::ref(done)); - Iterator const direct_result= - parallel_find_impl(first,mid_point,match,done); - return (direct_result==mid_point)? - async_result.get():direct_result; + try { + unsigned long const length = std::distance(first, last); + unsigned long const min_per_thread = 25; + if (length < (2 * min_per_thread)) { + for (; (first != last) && !done.load(); ++first) { + if (*first == match) { + done = true; + return first; } + } + return last; } - catch(...) - { - done=true; - throw; + else { + Iterator const mid_point = first + (length / 2); + std::future async_result = + std::async(¶llel_find_impl, + mid_point, + last, + match, + std::ref(done)); + Iterator const direct_result = + parallel_find_impl(first, mid_point, match, done); + return (direct_result == mid_point) ? async_result.get() : direct_result; } + } + catch (...) { + done = true; + throw; + } } -template -Iterator parallel_find(Iterator first,Iterator last,MatchType match) +template +Iterator +parallel_find(Iterator first, Iterator last, MatchType match) { - std::atomic done(false); - return parallel_find_impl(first,last,match,done); + std::atomic done(false); + return parallel_find_impl(first, last, match, done); } diff --git a/source/listing_8.11.cpp b/source/listing_8.11.cpp index 8595714..b6a6ebb 100644 --- a/source/listing_8.11.cpp +++ b/source/listing_8.11.cpp @@ -1,93 +1,83 @@ -template -void parallel_partial_sum(Iterator first,Iterator last) +template +void +parallel_partial_sum(Iterator first, Iterator last) { - typedef typename Iterator::value_type value_type; - struct process_chunk + typedef typename Iterator::value_type value_type; + struct process_chunk { + void operator()(Iterator begin, + Iterator last, + std::future* previous_end_value, + std::promise* end_value) { - void operator()(Iterator begin,Iterator last, - std::future* previous_end_value, - std::promise* end_value) - { - try - { - Iterator end=last; - ++end; - std::partial_sum(begin,end,begin); - if(previous_end_value) - { - value_type& addend=previous_end_value->get(); - *last+=addend; - if(end_value) - { - end_value->set_value(*last); - } - std::for_each(begin,last,[addend](value_type& item) - { - item+=addend; - }); - } - else if(end_value) - { - end_value->set_value(*last); - } - } - catch(...) - { - if(end_value) - { - end_value->set_exception(std::current_exception()); - } - else - { - throw; - } - } + try { + Iterator end = last; + ++end; + std::partial_sum(begin, end, begin); + if (previous_end_value) { + value_type& addend = previous_end_value->get(); + *last += addend; + if (end_value) { + end_value->set_value(*last); + } + std::for_each( + begin, last, [addend](value_type& item) { item += addend; }); } - }; - - unsigned long const length=std::distance(first,last); - - if(!length) - return last; - - unsigned long const min_per_thread=25; - unsigned long const max_threads= - (length+min_per_thread-1)/min_per_thread; - - unsigned long const hardware_threads= - std::thread::hardware_concurrency(); - - unsigned long const num_threads= - std::min(hardware_threads!=0?hardware_threads:2,max_threads); - - unsigned long const block_size=length/num_threads; - - typedef typename Iterator::value_type value_type; - - std::vector threads(num_threads-1); - std::vector > - end_values(num_threads-1); - std::vector > - previous_end_values; - previous_end_values.reserve(num_threads-1); - join_threads joiner(threads); - - Iterator block_start=first; - for(unsigned long i=0;i<(num_threads-1);++i) - { - Iterator block_last=block_start; - std::advance(block_last,block_size-1); - threads[i]=std::thread(process_chunk(), - block_start,block_last, - (i!=0)?&previous_end_values[i-1]:0, - &end_values[i]); - block_start=block_last; - ++block_start; - previous_end_values.push_back(end_values[i].get_future()); + else if (end_value) { + end_value->set_value(*last); + } + } + catch (...) { + if (end_value) { + end_value->set_exception(std::current_exception()); + } + else { + throw; + } + } } - Iterator final_element=block_start; - std::advance(final_element,std::distance(block_start,last)-1); - process_chunk()(block_start,final_element, - (num_threads>1)?&previous_end_values.back():0, - 0); + }; + + unsigned long const length = std::distance(first, last); + + if (!length) + return last; + + unsigned long const min_per_thread = 25; + unsigned long const max_threads = + (length + min_per_thread - 1) / min_per_thread; + + unsigned long const hardware_threads = std::thread::hardware_concurrency(); + + unsigned long const num_threads = + std::min(hardware_threads != 0 ? hardware_threads : 2, max_threads); + + unsigned long const block_size = length / num_threads; + + typedef typename Iterator::value_type value_type; + + std::vector threads(num_threads - 1); + std::vector> end_values(num_threads - 1); + std::vector> previous_end_values; + previous_end_values.reserve(num_threads - 1); + join_threads joiner(threads); + + Iterator block_start = first; + for (unsigned long i = 0; i < (num_threads - 1); ++i) { + Iterator block_last = block_start; + std::advance(block_last, block_size - 1); + threads[i] = std::thread(process_chunk(), + block_start, + block_last, + (i != 0) ? &previous_end_values[i - 1] : 0, + &end_values[i]); + block_start = block_last; + ++block_start; + previous_end_values.push_back(end_values[i].get_future()); + } + Iterator final_element = block_start; + std::advance(final_element, std::distance(block_start, last) - 1); + process_chunk()(block_start, + final_element, + (num_threads > 1) ? &previous_end_values.back() : 0, + 0); } diff --git a/source/listing_8.12.cpp b/source/listing_8.12.cpp index 45b2d00..a6920a6 100644 --- a/source/listing_8.12.cpp +++ b/source/listing_8.12.cpp @@ -1,24 +1,22 @@ -class barrier -{ - unsigned const count; - std::atomic spaces; - std::atomic generation; +class barrier { + unsigned const count; + std::atomic spaces; + std::atomic generation; + public: - explicit barrier(unsigned count_): - count(count_),spaces(count),generation(0) - {} - void wait() - { - unsigned const my_generation=generation; - if(!--spaces) - { - spaces=count; - ++generation; - } - else - { - while(generation==my_generation) - std::this_thread::yield(); - } + explicit barrier(unsigned count_) + : count(count_), spaces(count), generation(0) + { + } + void wait() + { + unsigned const my_generation = generation; + if (!--spaces) { + spaces = count; + ++generation; } + else { + while (generation == my_generation) std::this_thread::yield(); + } + } }; diff --git a/source/listing_8.13.cpp b/source/listing_8.13.cpp index 7e6b366..501a9e6 100644 --- a/source/listing_8.13.cpp +++ b/source/listing_8.13.cpp @@ -2,97 +2,84 @@ #include #include -struct join_threads -{ - join_threads(std::vector&) - {} -}; - - -struct barrier -{ - std::atomic count; - std::atomic spaces; - std::atomic generation; - barrier(unsigned count_): - count(count_),spaces(count_),generation(0) - {} - void wait() - { - unsigned const gen=generation.load(); - if(!--spaces) - { - spaces=count.load(); - ++generation; - } - else - { - while(generation.load()==gen) - { - std::this_thread::yield(); - } - } - } - - void done_waiting() - { - --count; - if(!--spaces) - { - spaces=count.load(); - ++generation; - } - } +struct join_threads { + join_threads(std::vector&) {} }; -template -void parallel_partial_sum(Iterator first,Iterator last) -{ - typedef typename Iterator::value_type value_type; - - struct process_element - { - void operator()(Iterator first,Iterator last, - std::vector& buffer, - unsigned i,barrier& b) - { - value_type& ith_element=*(first+i); - bool update_source=false; - for(unsigned step=0,stride=1;stride<=i;++step,stride*=2) - { - value_type const& source=(step%2)? - buffer[i]:ith_element; - value_type& dest=(step%2)? - ith_element:buffer[i]; - value_type const& addend=(step%2)? - buffer[i-stride]:*(first+i-stride); - dest=source+addend; - update_source=!(step%2); - b.wait(); - } - if(update_source) - { - ith_element=buffer[i]; - } - b.done_waiting(); - } - }; - - unsigned long const length=std::distance(first,last); - - if(length<=1) - return; - - std::vector buffer(length); - barrier b(length); - std::vector threads(length-1); - join_threads joiner(threads); - - Iterator block_start=first; - for(unsigned long i=0;i<(length-1);++i) - { - threads[i]=std::thread(process_element(),first,last, - std::ref(buffer),i,std::ref(b)); +struct barrier { + std::atomic count; + std::atomic spaces; + std::atomic generation; + barrier(unsigned count_) : count(count_), spaces(count_), generation(0) {} + void wait() + { + unsigned const gen = generation.load(); + if (!--spaces) { + spaces = count.load(); + ++generation; } - process_element()(first,last,buffer,length-1,b); + else { + while (generation.load() == gen) { + std::this_thread::yield(); + } + } + } + + void done_waiting() + { + --count; + if (!--spaces) { + spaces = count.load(); + ++generation; + } + } +}; + +template +void +parallel_partial_sum(Iterator first, Iterator last) +{ + typedef typename Iterator::value_type value_type; + + struct process_element { + void operator()(Iterator first, + Iterator last, + std::vector& buffer, + unsigned i, + barrier& b) + { + value_type& ith_element = *(first + i); + bool update_source = false; + for (unsigned step = 0, stride = 1; stride <= i; ++step, stride *= 2) { + value_type const& source = (step % 2) ? buffer[i] : ith_element; + value_type& dest = (step % 2) ? ith_element : buffer[i]; + value_type const& addend = + (step % 2) ? buffer[i - stride] : *(first + i - stride); + dest = source + addend; + update_source = !(step % 2); + b.wait(); + } + if (update_source) { + ith_element = buffer[i]; + } + b.done_waiting(); + } + }; + + unsigned long const length = std::distance(first, last); + + if (length <= 1) + return; + + std::vector buffer(length); + barrier b(length); + std::vector threads(length - 1); + join_threads joiner(threads); + + Iterator block_start = first; + for (unsigned long i = 0; i < (length - 1); ++i) { + threads[i] = std::thread( + process_element(), first, last, std::ref(buffer), i, std::ref(b)); + } + process_element()(first, last, buffer, length - 1, b); } diff --git a/source/listing_8.2.cpp b/source/listing_8.2.cpp index 559f1ad..ba664ed 100644 --- a/source/listing_8.2.cpp +++ b/source/listing_8.2.cpp @@ -1,49 +1,48 @@ -template -struct accumulate_block -{ - void operator()(Iterator first,Iterator last,T& result) - { - result=std::accumulate(first,last,result); - } +template +struct accumulate_block { + void operator()(Iterator first, Iterator last, T& result) + { + result = std::accumulate(first, last, result); + } }; -template -T parallel_accumulate(Iterator first,Iterator last,T init) +template +T +parallel_accumulate(Iterator first, Iterator last, T init) { - unsigned long const length=std::distance(first,last); + unsigned long const length = std::distance(first, last); - if(!length) - return init; + if (!length) + return init; - unsigned long const min_per_thread=25; - unsigned long const max_threads= - (length+min_per_thread-1)/min_per_thread; + unsigned long const min_per_thread = 25; + unsigned long const max_threads = + (length + min_per_thread - 1) / min_per_thread; - unsigned long const hardware_threads= - std::thread::hardware_concurrency(); + unsigned long const hardware_threads = std::thread::hardware_concurrency(); - unsigned long const num_threads= - std::min(hardware_threads!=0?hardware_threads:2,max_threads); + unsigned long const num_threads = + std::min(hardware_threads != 0 ? hardware_threads : 2, max_threads); - unsigned long const block_size=length/num_threads; + unsigned long const block_size = length / num_threads; - std::vector results(num_threads); - std::vector threads(num_threads-1); + std::vector results(num_threads); + std::vector threads(num_threads - 1); - Iterator block_start=first; - for(unsigned long i=0;i<(num_threads-1);++i) - { - Iterator block_end=block_start; - std::advance(block_end,block_size); - threads[i]=std::thread( - accumulate_block(), - block_start,block_end,std::ref(results[i])); - block_start=block_end; - } - accumulate_block()(block_start,last,results[num_threads-1]); + Iterator block_start = first; + for (unsigned long i = 0; i < (num_threads - 1); ++i) { + Iterator block_end = block_start; + std::advance(block_end, block_size); + threads[i] = std::thread(accumulate_block(), + block_start, + block_end, + std::ref(results[i])); + block_start = block_end; + } + accumulate_block()(block_start, last, results[num_threads - 1]); - std::for_each(threads.begin(),threads.end(), - std::mem_fn(&std::thread::join)); + std::for_each( + threads.begin(), threads.end(), std::mem_fn(&std::thread::join)); - return std::accumulate(results.begin(),results.end(),init); + return std::accumulate(results.begin(), results.end(), init); } diff --git a/source/listing_8.3.cpp b/source/listing_8.3.cpp index 30e0386..6a31dcb 100644 --- a/source/listing_8.3.cpp +++ b/source/listing_8.3.cpp @@ -1,56 +1,53 @@ -template -struct accumulate_block -{ - T operator()(Iterator first,Iterator last) - { - return std::accumulate(first,last,T()); - } +template +struct accumulate_block { + T operator()(Iterator first, Iterator last) + { + return std::accumulate(first, last, T()); + } }; -template -T parallel_accumulate(Iterator first,Iterator last,T init) +template +T +parallel_accumulate(Iterator first, Iterator last, T init) { - unsigned long const length=std::distance(first,last); + unsigned long const length = std::distance(first, last); - if(!length) - return init; + if (!length) + return init; - unsigned long const min_per_thread=25; - unsigned long const max_threads= - (length+min_per_thread-1)/min_per_thread; + unsigned long const min_per_thread = 25; + unsigned long const max_threads = + (length + min_per_thread - 1) / min_per_thread; - unsigned long const hardware_threads= - std::thread::hardware_concurrency(); + unsigned long const hardware_threads = std::thread::hardware_concurrency(); - unsigned long const num_threads= - std::min(hardware_threads!=0?hardware_threads:2,max_threads); + unsigned long const num_threads = + std::min(hardware_threads != 0 ? hardware_threads : 2, max_threads); - unsigned long const block_size=length/num_threads; + unsigned long const block_size = length / num_threads; - std::vector > futures(num_threads-1); - std::vector threads(num_threads-1); + std::vector> futures(num_threads - 1); + std::vector threads(num_threads - 1); - Iterator block_start=first; - for(unsigned long i=0;i<(num_threads-1);++i) - { - Iterator block_end=block_start; - std::advance(block_end,block_size); - std::packaged_task task( - accumulate_block()); - futures[i]=task.get_future(); - threads[i]=std::thread(std::move(task),block_start,block_end); - block_start=block_end; - } - T last_result=accumulate_block()(block_start,last); + Iterator block_start = first; + for (unsigned long i = 0; i < (num_threads - 1); ++i) { + Iterator block_end = block_start; + std::advance(block_end, block_size); + std::packaged_task task( + accumulate_block()); + futures[i] = task.get_future(); + threads[i] = std::thread(std::move(task), block_start, block_end); + block_start = block_end; + } + T last_result = accumulate_block()(block_start, last); - std::for_each(threads.begin(),threads.end(), - std::mem_fn(&std::thread::join)); + std::for_each( + threads.begin(), threads.end(), std::mem_fn(&std::thread::join)); - T result=init; - for(unsigned long i=0;i<(num_threads-1);++i) - { - result+=futures[i].get(); - } - result += last_result; - return result; + T result = init; + for (unsigned long i = 0; i < (num_threads - 1); ++i) { + result += futures[i].get(); + } + result += last_result; + return result; } diff --git a/source/listing_8.4.cpp b/source/listing_8.4.cpp index 852af26..ac39101 100644 --- a/source/listing_8.4.cpp +++ b/source/listing_8.4.cpp @@ -1,44 +1,42 @@ -template -T parallel_accumulate(Iterator first,Iterator last,T init) +template +T +parallel_accumulate(Iterator first, Iterator last, T init) { - unsigned long const length=std::distance(first,last); + unsigned long const length = std::distance(first, last); - if(!length) - return init; + if (!length) + return init; - unsigned long const min_per_thread=25; - unsigned long const max_threads= - (length+min_per_thread-1)/min_per_thread; + unsigned long const min_per_thread = 25; + unsigned long const max_threads = + (length + min_per_thread - 1) / min_per_thread; - unsigned long const hardware_threads= - std::thread::hardware_concurrency(); + unsigned long const hardware_threads = std::thread::hardware_concurrency(); - unsigned long const num_threads= - std::min(hardware_threads!=0?hardware_threads:2,max_threads); + unsigned long const num_threads = + std::min(hardware_threads != 0 ? hardware_threads : 2, max_threads); - unsigned long const block_size=length/num_threads; + unsigned long const block_size = length / num_threads; - std::vector > futures(num_threads-1); - std::vector threads(num_threads-1); - join_threads joiner(threads); + std::vector> futures(num_threads - 1); + std::vector threads(num_threads - 1); + join_threads joiner(threads); - Iterator block_start=first; - for(unsigned long i=0;i<(num_threads-1);++i) - { - Iterator block_end=block_start; - std::advance(block_end,block_size); - std::packaged_task task( - accumulate_block()); - futures[i]=task.get_future(); - threads[i]=std::thread(std::move(task),block_start,block_end); - block_start=block_end; - } - T last_result=accumulate_block()(block_start,last); - T result=init; - for(unsigned long i=0;i<(num_threads-1);++i) - { - result+=futures[i].get(); - } - result += last_result; - return result; + Iterator block_start = first; + for (unsigned long i = 0; i < (num_threads - 1); ++i) { + Iterator block_end = block_start; + std::advance(block_end, block_size); + std::packaged_task task( + accumulate_block()); + futures[i] = task.get_future(); + threads[i] = std::thread(std::move(task), block_start, block_end); + block_start = block_end; + } + T last_result = accumulate_block()(block_start, last); + T result = init; + for (unsigned long i = 0; i < (num_threads - 1); ++i) { + result += futures[i].get(); + } + result += last_result; + return result; } diff --git a/source/listing_8.5.cpp b/source/listing_8.5.cpp index a5248a5..636c46a 100644 --- a/source/listing_8.5.cpp +++ b/source/listing_8.5.cpp @@ -1,20 +1,18 @@ -template -T parallel_accumulate(Iterator first,Iterator last,T init) +template +T +parallel_accumulate(Iterator first, Iterator last, T init) { - unsigned long const length=std::distance(first,last); - unsigned long const max_chunk_size=25; - if(length<=max_chunk_size) - { - return std::accumulate(first,last,init); - } - else - { - Iterator mid_point=first; - std::advance(mid_point,length/2); - std::future first_half_result= - std::async(parallel_accumulate, - first,mid_point,init); - T second_half_result=parallel_accumulate(mid_point,last,T()); - return first_half_result.get()+second_half_result; - } + unsigned long const length = std::distance(first, last); + unsigned long const max_chunk_size = 25; + if (length <= max_chunk_size) { + return std::accumulate(first, last, init); + } + else { + Iterator mid_point = first; + std::advance(mid_point, length / 2); + std::future first_half_result = + std::async(parallel_accumulate, first, mid_point, init); + T second_half_result = parallel_accumulate(mid_point, last, T()); + return first_half_result.get() + second_half_result; + } } diff --git a/source/listing_8.6.cpp b/source/listing_8.6.cpp index 09751ef..94f6c4d 100644 --- a/source/listing_8.6.cpp +++ b/source/listing_8.6.cpp @@ -1,50 +1,48 @@ std::thread task_thread; std::atomic task_cancelled(false); -void gui_thread() +void +gui_thread() { - while(true) - { - event_data event=get_event(); - if(event.type==quit) - break; - process(event); - } + while (true) { + event_data event = get_event(); + if (event.type == quit) + break; + process(event); + } } -void task() +void +task() { - while(!task_complete() && !task_cancelled) - { - do_next_operation(); - } - if(task_cancelled) - { - perform_cleanup(); - } - else - { - post_gui_event(task_complete); - } + while (!task_complete() && !task_cancelled) { + do_next_operation(); + } + if (task_cancelled) { + perform_cleanup(); + } + else { + post_gui_event(task_complete); + } } -void process(event_data const& event) +void +process(event_data const& event) { - switch(event.type) - { - case start_task: - task_cancelled=false; - task_thread=std::thread(task); - break; - case stop_task: - task_cancelled=true; - task_thread.join(); - break; - case task_complete: - task_thread.join(); - display_results(); - break; - default: - //... - } + switch (event.type) { + case start_task: + task_cancelled = false; + task_thread = std::thread(task); + break; + case stop_task: + task_cancelled = true; + task_thread.join(); + break; + case task_complete: + task_thread.join(); + display_results(); + break; + default: + //... + } } diff --git a/source/listing_8.7.cpp b/source/listing_8.7.cpp index 0a1a916..ca63bce 100644 --- a/source/listing_8.7.cpp +++ b/source/listing_8.7.cpp @@ -1,44 +1,39 @@ -template -void parallel_for_each(Iterator first,Iterator last,Func f) +template +void +parallel_for_each(Iterator first, Iterator last, Func f) { - unsigned long const length=std::distance(first,last); + unsigned long const length = std::distance(first, last); - if(!length) - return; + if (!length) + return; - unsigned long const min_per_thread=25; - unsigned long const max_threads= - (length+min_per_thread-1)/min_per_thread; + unsigned long const min_per_thread = 25; + unsigned long const max_threads = + (length + min_per_thread - 1) / min_per_thread; - unsigned long const hardware_threads= - std::thread::hardware_concurrency(); + unsigned long const hardware_threads = std::thread::hardware_concurrency(); - unsigned long const num_threads= - std::min(hardware_threads!=0?hardware_threads:2,max_threads); + unsigned long const num_threads = + std::min(hardware_threads != 0 ? hardware_threads : 2, max_threads); - unsigned long const block_size=length/num_threads; + unsigned long const block_size = length / num_threads; - std::vector > futures(num_threads-1); - std::vector threads(num_threads-1); - join_threads joiner(threads); + std::vector> futures(num_threads - 1); + std::vector threads(num_threads - 1); + join_threads joiner(threads); - Iterator block_start=first; - for(unsigned long i=0;i<(num_threads-1);++i) - { - Iterator block_end=block_start; - std::advance(block_end,block_size); - std::packaged_task task( - [=]() - { - std::for_each(block_start,block_end,f); - }); - futures[i]=task.get_future(); - threads[i]=std::thread(std::move(task)); - block_start=block_end; - } - std::for_each(block_start,last,f); - for(unsigned long i=0;i<(num_threads-1);++i) - { - futures[i].get(); - } + Iterator block_start = first; + for (unsigned long i = 0; i < (num_threads - 1); ++i) { + Iterator block_end = block_start; + std::advance(block_end, block_size); + std::packaged_task task( + [=]() { std::for_each(block_start, block_end, f); }); + futures[i] = task.get_future(); + threads[i] = std::thread(std::move(task)); + block_start = block_end; + } + std::for_each(block_start, last, f); + for (unsigned long i = 0; i < (num_threads - 1); ++i) { + futures[i].get(); + } } diff --git a/source/listing_8.8.cpp b/source/listing_8.8.cpp index f8ff7b0..3068390 100644 --- a/source/listing_8.8.cpp +++ b/source/listing_8.8.cpp @@ -1,24 +1,22 @@ -template -void parallel_for_each(Iterator first,Iterator last,Func f) +template +void +parallel_for_each(Iterator first, Iterator last, Func f) { - unsigned long const length=std::distance(first,last); + unsigned long const length = std::distance(first, last); - if(!length) - return; + if (!length) + return; - unsigned long const min_per_thread=25; + unsigned long const min_per_thread = 25; - if(length<(2*min_per_thread)) - { - std::for_each(first,last,f); - } - else - { - Iterator const mid_point=first+length/2; - std::future first_half= - std::async(¶llel_for_each, - first,mid_point,f); - parallel_for_each(mid_point,last,f); - first_half.get(); - } + if (length < (2 * min_per_thread)) { + std::for_each(first, last, f); + } + else { + Iterator const mid_point = first + length / 2; + std::future first_half = + std::async(¶llel_for_each, first, mid_point, f); + parallel_for_each(mid_point, last, f); + first_half.get(); + } } diff --git a/source/listing_8.9.cpp b/source/listing_8.9.cpp index 1750296..f5352ec 100644 --- a/source/listing_8.9.cpp +++ b/source/listing_8.9.cpp @@ -1,76 +1,68 @@ -template -Iterator parallel_find(Iterator first,Iterator last,MatchType match) +template +Iterator +parallel_find(Iterator first, Iterator last, MatchType match) { - struct find_element + struct find_element { + void operator()(Iterator begin, + Iterator end, + MatchType match, + std::promise* result, + std::atomic* done_flag) { - void operator()(Iterator begin,Iterator end, - MatchType match, - std::promise* result, - std::atomic* done_flag) - { - try - { - for(;(begin!=end) && !done_flag->load();++begin) - { - if(*begin==match) - { - result->set_value(begin); - done_flag->store(true); - return; - } - } - } - catch(...) - { - try - { - result->set_exception(std::current_exception()); - done_flag->store(true); - } - catch(...) - {} - } + try { + for (; (begin != end) && !done_flag->load(); ++begin) { + if (*begin == match) { + result->set_value(begin); + done_flag->store(true); + return; + } } - }; - - unsigned long const length=std::distance(first,last); - - if(!length) - return last; - - unsigned long const min_per_thread=25; - unsigned long const max_threads= - (length+min_per_thread-1)/min_per_thread; - - unsigned long const hardware_threads= - std::thread::hardware_concurrency(); - - unsigned long const num_threads= - std::min(hardware_threads!=0?hardware_threads:2,max_threads); - - unsigned long const block_size=length/num_threads; - - std::promise result; - std::atomic done_flag(false); - std::vector threads(num_threads-1); - { - join_threads joiner(threads); - - Iterator block_start=first; - for(unsigned long i=0;i<(num_threads-1);++i) - { - Iterator block_end=block_start; - std::advance(block_end,block_size); - threads[i]=std::thread(find_element(), - block_start,block_end,match, - &result,&done_flag); - block_start=block_end; + } + catch (...) { + try { + result->set_exception(std::current_exception()); + done_flag->store(true); } - find_element()(block_start,last,match,&result,&done_flag); + catch (...) { + } + } } - if(!done_flag.load()) - { - return last; + }; + + unsigned long const length = std::distance(first, last); + + if (!length) + return last; + + unsigned long const min_per_thread = 25; + unsigned long const max_threads = + (length + min_per_thread - 1) / min_per_thread; + + unsigned long const hardware_threads = std::thread::hardware_concurrency(); + + unsigned long const num_threads = + std::min(hardware_threads != 0 ? hardware_threads : 2, max_threads); + + unsigned long const block_size = length / num_threads; + + std::promise result; + std::atomic done_flag(false); + std::vector threads(num_threads - 1); + { + join_threads joiner(threads); + + Iterator block_start = first; + for (unsigned long i = 0; i < (num_threads - 1); ++i) { + Iterator block_end = block_start; + std::advance(block_end, block_size); + threads[i] = std::thread( + find_element(), block_start, block_end, match, &result, &done_flag); + block_start = block_end; } - return result.get_future().get(); + find_element()(block_start, last, match, &result, &done_flag); + } + if (!done_flag.load()) { + return last; + } + return result.get_future().get(); } diff --git a/source/listing_9.1.cpp b/source/listing_9.1.cpp index dd3ca84..0598be9 100644 --- a/source/listing_9.1.cpp +++ b/source/listing_9.1.cpp @@ -1,53 +1,42 @@ -class thread_pool -{ - std::atomic_bool done; - thread_safe_queue > work_queue; - std::vector threads; - join_threads joiner; +class thread_pool { + std::atomic_bool done; + thread_safe_queue> work_queue; + std::vector threads; + join_threads joiner; - void worker_thread() - { - while(!done) - { - std::function task; - if(work_queue.try_pop(task)) - { - task(); - } - else - { - std::this_thread::yield(); - } - } + void worker_thread() + { + while (!done) { + std::function task; + if (work_queue.try_pop(task)) { + task(); + } + else { + std::this_thread::yield(); + } } + } + public: - thread_pool(): - done(false),joiner(threads) - { - unsigned const thread_count=std::thread::hardware_concurrency(); - try - { - for(unsigned i=0;i - void submit(FunctionType f) - { - work_queue.push(std::function(f)); - } + template + void submit(FunctionType f) + { + work_queue.push(std::function(f)); + } }; diff --git a/source/listing_9.10.cpp b/source/listing_9.10.cpp index f9641ad..ea1f223 100644 --- a/source/listing_9.10.cpp +++ b/source/listing_9.10.cpp @@ -1,9 +1,10 @@ -void interruptible_wait(std::condition_variable& cv, - std::unique_lock& lk) +void +interruptible_wait(std::condition_variable& cv, + std::unique_lock& lk) { - interruption_point(); - this_thread_interrupt_flag.set_condition_variable(cv); - cv.wait(lk); - this_thread_interrupt_flag.clear_condition_variable(); - interruption_point(); + interruption_point(); + this_thread_interrupt_flag.set_condition_variable(cv); + cv.wait(lk); + this_thread_interrupt_flag.clear_condition_variable(); + interruption_point(); } diff --git a/source/listing_9.11.cpp b/source/listing_9.11.cpp index ea05a8a..e23e63a 100644 --- a/source/listing_9.11.cpp +++ b/source/listing_9.11.cpp @@ -1,57 +1,50 @@ -class interrupt_flag -{ - std::atomic flag; - std::condition_variable* thread_cond; - std::mutex set_clear_mutex; +class interrupt_flag { + std::atomic flag; + std::condition_variable* thread_cond; + std::mutex set_clear_mutex; public: - interrupt_flag(): - thread_cond(0) - {} + interrupt_flag() : thread_cond(0) {} - void set() - { - flag.store(true,std::memory_order_relaxed); - std::lock_guard lk(set_clear_mutex); - if(thread_cond) - { - thread_cond->notify_all(); - } + void set() + { + flag.store(true, std::memory_order_relaxed); + std::lock_guard lk(set_clear_mutex); + if (thread_cond) { + thread_cond->notify_all(); } + } - bool is_set() const + bool is_set() const { return flag.load(std::memory_order_relaxed); } + + void set_condition_variable(std::condition_variable& cv) + { + std::lock_guard lk(set_clear_mutex); + thread_cond = &cv; + } + + void clear_condition_variable() + { + std::lock_guard lk(set_clear_mutex); + thread_cond = 0; + } + + struct clear_cv_on_destruct { + ~clear_cv_on_destruct() { - return flag.load(std::memory_order_relaxed); + this_thread_interrupt_flag.clear_condition_variable(); } - - void set_condition_variable(std::condition_variable& cv) - { - std::lock_guard lk(set_clear_mutex); - thread_cond=&cv; - } - - void clear_condition_variable() - { - std::lock_guard lk(set_clear_mutex); - thread_cond=0; - } - - struct clear_cv_on_destruct - { - ~clear_cv_on_destruct() - { - this_thread_interrupt_flag.clear_condition_variable(); - } - }; + }; }; -void interruptible_wait(std::condition_variable& cv, - std::unique_lock& lk) +void +interruptible_wait(std::condition_variable& cv, + std::unique_lock& lk) { - interruption_point(); - this_thread_interrupt_flag.set_condition_variable(cv); - interrupt_flag::clear_cv_on_destruct guard; - interruption_point(); - cv.wait_for(lk,std::chrono::milliseconds(1)); - interruption_point(); + interruption_point(); + this_thread_interrupt_flag.set_condition_variable(cv); + interrupt_flag::clear_cv_on_destruct guard; + interruption_point(); + cv.wait_for(lk, std::chrono::milliseconds(1)); + interruption_point(); } diff --git a/source/listing_9.12.cpp b/source/listing_9.12.cpp index 29101ce..e9ea9c5 100644 --- a/source/listing_9.12.cpp +++ b/source/listing_9.12.cpp @@ -1,77 +1,67 @@ -class interrupt_flag -{ - std::atomic flag; - std::condition_variable* thread_cond; - std::condition_variable_any* thread_cond_any; - std::mutex set_clear_mutex; +class interrupt_flag { + std::atomic flag; + std::condition_variable* thread_cond; + std::condition_variable_any* thread_cond_any; + std::mutex set_clear_mutex; public: - interrupt_flag(): - Interrupting threads - thread_cond(0),thread_cond_any(0) - {} + interrupt_flag() : Interrupting threads thread_cond(0), thread_cond_any(0) {} - void set() - { - flag.store(true,std::memory_order_relaxed); - std::lock_guard lk(set_clear_mutex); - if(thread_cond) - { - thread_cond->notify_all(); - } - else if(thread_cond_any) - { - thread_cond_any->notify_all(); - } + void set() + { + flag.store(true, std::memory_order_relaxed); + std::lock_guard lk(set_clear_mutex); + if (thread_cond) { + thread_cond->notify_all(); } - - template - void wait(std::condition_variable_any& cv,Lockable& lk) - { - struct custom_lock - { - interrupt_flag* self; - Lockable& lk; - - custom_lock(interrupt_flag* self_, - std::condition_variable_any& cond, - Lockable& lk_): - self(self_),lk(lk_) - { - self->set_clear_mutex.lock(); - self->thread_cond_any=&cond; - } - - void unlock() - { - lk.unlock(); - self->set_clear_mutex.unlock(); - } - - void lock() - { - std::lock(self->set_clear_mutex,lk); - } - - ~custom_lock() - { - self->thread_cond_any=0; - self->set_clear_mutex.unlock(); - } - }; - - custom_lock cl(this,cv,lk); - interruption_point(); - cv.wait(cl); - interruption_point(); + else if (thread_cond_any) { + thread_cond_any->notify_all(); } + } - // rest as before + template + void wait(std::condition_variable_any& cv, Lockable& lk) + { + struct custom_lock { + interrupt_flag* self; + Lockable& lk; + + custom_lock(interrupt_flag* self_, + std::condition_variable_any& cond, + Lockable& lk_) + : self(self_), lk(lk_) + { + self->set_clear_mutex.lock(); + self->thread_cond_any = &cond; + } + + void unlock() + { + lk.unlock(); + self->set_clear_mutex.unlock(); + } + + void lock() { std::lock(self->set_clear_mutex, lk); } + + ~custom_lock() + { + self->thread_cond_any = 0; + self->set_clear_mutex.unlock(); + } + }; + + custom_lock cl(this, cv, lk); + interruption_point(); + cv.wait(cl); + interruption_point(); + } + + // rest as before }; -template -void interruptible_wait(std::condition_variable_any& cv, - Lockable& lk) +template +void +interruptible_wait(std::condition_variable_any& cv, Lockable& lk) { - this_thread_interrupt_flag.wait(cv,lk); + this_thread_interrupt_flag.wait(cv, lk); } diff --git a/source/listing_9.13.cpp b/source/listing_9.13.cpp index 5ec1da0..9351ec3 100644 --- a/source/listing_9.13.cpp +++ b/source/listing_9.13.cpp @@ -1,38 +1,35 @@ std::mutex config_mutex; std::vector background_threads; -void background_thread(int disk_id) +void +background_thread(int disk_id) { - while(true) - { - interruption_point(); - fs_change fsc=get_fs_changes(disk_id); - if(fsc.has_changes()) - { - update_index(fsc); - } + while (true) { + interruption_point(); + fs_change fsc = get_fs_changes(disk_id); + if (fsc.has_changes()) { + update_index(fsc); } + } } -void start_background_processing() +void +start_background_processing() { - background_threads.push_back( - interruptible_thread(background_thread,disk_1)); - background_threads.push_back( - interruptible_thread(background_thread,disk_2)); + background_threads.push_back(interruptible_thread(background_thread, disk_1)); + background_threads.push_back(interruptible_thread(background_thread, disk_2)); } -int main() +int +main() { - start_background_processing(); - process_gui_until_exit(); - std::unique_lock lk(config_mutex); - for(unsigned i=0;i lk(config_mutex); + for (unsigned i = 0; i < background_threads.size(); ++i) { + background_threads[i].interrupt(); + } + for (unsigned i = 0; i < background_threads.size(); ++i) { + background_threads[i].join(); + } } diff --git a/source/listing_9.2.cpp b/source/listing_9.2.cpp index bb32073..4dd6138 100644 --- a/source/listing_9.2.cpp +++ b/source/listing_9.2.cpp @@ -1,62 +1,57 @@ #include -#include -#include #include +#include #include -#include +#include + +class function_wrapper { + struct impl_base { + virtual void call() = 0; + virtual ~impl_base() {} + }; + std::unique_ptr impl; + template + struct impl_type : impl_base { + F f; + impl_type(F&& f_) : f(std::move(f_)) {} + void call() { f(); } + }; -class function_wrapper -{ - struct impl_base { - virtual void call()=0; - virtual ~impl_base() {} - }; - std::unique_ptr impl; - template - struct impl_type: impl_base - { - F f; - impl_type(F&& f_): f(std::move(f_)) {} - void call() { f(); } - }; public: - template - function_wrapper(F&& f): - impl(new impl_type(std::move(f))) - {} + template + function_wrapper(F&& f) : impl(new impl_type(std::move(f))) + { + } - void call() { impl->call(); } + void call() { impl->call(); } - function_wrapper(function_wrapper&& other): - impl(std::move(other.impl)) - {} + function_wrapper(function_wrapper&& other) : impl(std::move(other.impl)) {} - function_wrapper& operator=(function_wrapper&& other) - { - impl=std::move(other.impl); - return *this; - } + function_wrapper& operator=(function_wrapper&& other) + { + impl = std::move(other.impl); + return *this; + } - function_wrapper(const function_wrapper&)=delete; - function_wrapper(function_wrapper&)=delete; - function_wrapper& operator=(const function_wrapper&)=delete; + function_wrapper(const function_wrapper&) = delete; + function_wrapper(function_wrapper&) = delete; + function_wrapper& operator=(const function_wrapper&) = delete; }; -class thread_pool -{ +class thread_pool { public: - std::deque work_queue; + std::deque work_queue; - template - std::future::type> - submit(FunctionType f) - { - typedef typename std::result_of::type result_type; - - std::packaged_task task(std::move(f)); - std::future res(task.get_future()); - work_queue.push_back(std::move(task)); - return res; - } - // rest as before + template + std::future::type> submit( + FunctionType f) + { + typedef typename std::result_of::type result_type; + + std::packaged_task task(std::move(f)); + std::future res(task.get_future()); + work_queue.push_back(std::move(task)); + return res; + } + // rest as before }; diff --git a/source/listing_9.3.cpp b/source/listing_9.3.cpp index 9a16073..f3ca30a 100644 --- a/source/listing_9.3.cpp +++ b/source/listing_9.3.cpp @@ -1,31 +1,30 @@ -template -T parallel_accumulate(Iterator first,Iterator last,T init) +template +T +parallel_accumulate(Iterator first, Iterator last, T init) { - unsigned long const length=std::distance(first,last); + unsigned long const length = std::distance(first, last); - if(!length) - return init; + if (!length) + return init; - unsigned long const block_size=25; - unsigned long const num_blocks=(length+block_size-1)/block_size; + unsigned long const block_size = 25; + unsigned long const num_blocks = (length + block_size - 1) / block_size; - std::vector > futures(num_blocks-1); - thread_pool pool; + std::vector> futures(num_blocks - 1); + thread_pool pool; - Iterator block_start=first; - for(unsigned long i=0;i<(num_threads-1);++i) - { - Iterator block_end=block_start; - std::advance(block_end,block_size); - futures[i]=pool.submit(accumulate_block()); - block_start=block_end; - } - T last_result=accumulate_block()(block_start,last); - T result=init; - for(unsigned long i=0;i<(num_blocks-1);++i) - { - result+=futures[i].get(); - } - result += last_result; - return result; + Iterator block_start = first; + for (unsigned long i = 0; i < (num_threads - 1); ++i) { + Iterator block_end = block_start; + std::advance(block_end, block_size); + futures[i] = pool.submit(accumulate_block()); + block_start = block_end; + } + T last_result = accumulate_block()(block_start, last); + T result = init; + for (unsigned long i = 0; i < (num_blocks - 1); ++i) { + result += futures[i].get(); + } + result += last_result; + return result; } diff --git a/source/listing_9.4.cpp b/source/listing_9.4.cpp index 9d1beea..3d0cf34 100644 --- a/source/listing_9.4.cpp +++ b/source/listing_9.4.cpp @@ -1,12 +1,11 @@ -void thread_pool::run_pending_task() +void +thread_pool::run_pending_task() { - function_wrapper task; - if(work_queue.try_pop(task)) - { - task(); - } - else - { - std::this_thread::yield(); - } + function_wrapper task; + if (work_queue.try_pop(task)) { + task(); + } + else { + std::this_thread::yield(); + } } diff --git a/source/listing_9.5.cpp b/source/listing_9.5.cpp index 83b83b4..45ba6b3 100644 --- a/source/listing_9.5.cpp +++ b/source/listing_9.5.cpp @@ -1,58 +1,49 @@ -template -struct sorter -{ - thread_pool pool; - - std::list do_sort(std::list& chunk_data) - { - if(chunk_data.empty()) - { - return chunk_data; - } - - std::list result; - result.splice(result.begin(),chunk_data,chunk_data.begin()); - T const& partition_val=*result.begin(); - - typename std::list::iterator divide_point= - std::partition( - chunk_data.begin(),chunk_data.end(), - [&](T const& val){return val +struct sorter { + thread_pool pool; - std::list new_lower_chunk; - new_lower_chunk.splice( - new_lower_chunk.end(), - chunk_data,chunk_data.begin(), - divide_point); - - thread_pool::task_handle > new_lower= - pool.submit( - std::bind( - &sorter::do_sort,this, - std::move(new_lower_chunk))); - - std::list new_higher(do_sort(chunk_data)); - - result.splice(result.end(),new_higher); - while(!new_lower.is_ready()) - { - pool.run_pending_task(); - } - - result.splice(result.begin(),new_lower.get()); - return result; + std::list do_sort(std::list& chunk_data) + { + if (chunk_data.empty()) { + return chunk_data; } + + std::list result; + result.splice(result.begin(), chunk_data, chunk_data.begin()); + T const& partition_val = *result.begin(); + + typename std::list::iterator divide_point = + std::partition(chunk_data.begin(), chunk_data.end(), [&](T const& val) { + return val < partition_val; + }); + + std::list new_lower_chunk; + new_lower_chunk.splice( + new_lower_chunk.end(), chunk_data, chunk_data.begin(), divide_point); + + thread_pool::task_handle> new_lower = pool.submit( + std::bind(&sorter::do_sort, this, std::move(new_lower_chunk))); + + std::list new_higher(do_sort(chunk_data)); + + result.splice(result.end(), new_higher); + while (!new_lower.is_ready()) { + pool.run_pending_task(); + } + + result.splice(result.begin(), new_lower.get()); + return result; + } }; - -template -std::list parallel_quick_sort(std::list input) +template +std::list +parallel_quick_sort(std::list input) { - if(input.empty()) - { - return input; - } - sorter s; - - return s.do_sort(input); + if (input.empty()) { + return input; + } + sorter s; + + return s.do_sort(input); } diff --git a/source/listing_9.6.cpp b/source/listing_9.6.cpp index 840382d..311df48 100644 --- a/source/listing_9.6.cpp +++ b/source/listing_9.6.cpp @@ -1,58 +1,49 @@ -class thread_pool -{ - thread_safe_queue pool_work_queue; +class thread_pool { + thread_safe_queue pool_work_queue; - typedef std::queue local_queue_type; - static thread_local std::unique_ptr - local_work_queue; - - void worker_thread() - { - local_work_queue.reset(new local_queue_type); - - while(!done) - { - run_pending_task(); - } + typedef std::queue local_queue_type; + static thread_local std::unique_ptr local_work_queue; + + void worker_thread() + { + local_work_queue.reset(new local_queue_type); + + while (!done) { + run_pending_task(); } + } public: - template - std::future::type> - submit(FunctionType f) - { - typedef std::result_of::type result_type; - - std::packaged_task task(f); - std::future res(task.get_future()); - if(local_work_queue) - { - local_work_queue->push(std::move(task)); - } - else - { - pool_work_queue.push(std::move(task)); - } - return res; - } + template + std::future::type> submit(FunctionType f) + { + typedef std::result_of::type result_type; - void run_pending_task() - { - function_wrapper task; - if(local_work_queue && !local_work_queue->empty()) - { - task=std::move(local_work_queue->front()); - local_work_queue->pop(); - task(); - } - else if(pool_work_queue.try_pop(task)) - { - task(); - } - else - { - std::this_thread::yield(); - } + std::packaged_task task(f); + std::future res(task.get_future()); + if (local_work_queue) { + local_work_queue->push(std::move(task)); } - // rest as before + else { + pool_work_queue.push(std::move(task)); + } + return res; + } + + void run_pending_task() + { + function_wrapper task; + if (local_work_queue && !local_work_queue->empty()) { + task = std::move(local_work_queue->front()); + local_work_queue->pop(); + task(); + } + else if (pool_work_queue.try_pop(task)) { + task(); + } + else { + std::this_thread::yield(); + } + } + // rest as before }; diff --git a/source/listing_9.7.cpp b/source/listing_9.7.cpp index 2ebdb29..cdb3974 100644 --- a/source/listing_9.7.cpp +++ b/source/listing_9.7.cpp @@ -1,53 +1,48 @@ -class work_stealing_queue -{ +class work_stealing_queue { private: - typedef function_wrapper data_type; - std::deque the_queue; - mutable std::mutex the_mutex; - + typedef function_wrapper data_type; + std::deque the_queue; + mutable std::mutex the_mutex; + public: - work_stealing_queue() - {} + work_stealing_queue() {} - work_stealing_queue(const work_stealing_queue& other)=delete; - work_stealing_queue& operator=( - const work_stealing_queue& other)=delete; + work_stealing_queue(const work_stealing_queue& other) = delete; + work_stealing_queue& operator=(const work_stealing_queue& other) = delete; - void push(data_type data) - { - std::lock_guard lock(the_mutex); - the_queue.push_front(std::move(data)); + void push(data_type data) + { + std::lock_guard lock(the_mutex); + the_queue.push_front(std::move(data)); + } + + bool empty() const + { + std::lock_guard lock(the_mutex); + return the_queue.empty(); + } + + bool try_pop(data_type& res) + { + std::lock_guard lock(the_mutex); + if (the_queue.empty()) { + return false; } - bool empty() const - { - std::lock_guard lock(the_mutex); - return the_queue.empty(); + res = std::move(the_queue.front()); + the_queue.pop_front(); + return true; + } + + bool try_steal(data_type& res) + { + std::lock_guard lock(the_mutex); + if (the_queue.empty()) { + return false; } - bool try_pop(data_type& res) - { - std::lock_guard lock(the_mutex); - if(the_queue.empty()) - { - return false; - } - - res=std::move(the_queue.front()); - the_queue.pop_front(); - return true; - } - - bool try_steal(data_type& res) - { - std::lock_guard lock(the_mutex); - if(the_queue.empty()) - { - return false; - } - - res=std::move(the_queue.back()); - the_queue.pop_back(); - return true; - } + res = std::move(the_queue.back()); + the_queue.pop_back(); + return true; + } }; diff --git a/source/listing_9.8.cpp b/source/listing_9.8.cpp index f2bbf09..a066a5d 100644 --- a/source/listing_9.8.cpp +++ b/source/listing_9.8.cpp @@ -1,112 +1,94 @@ -class thread_pool -{ - typedef function_wrapper task_type; - - std::atomic_bool done; - thread_safe_queue pool_work_queue; - std::vector > queues; - std::vector threads; - join_threads joiner; +class thread_pool { + typedef function_wrapper task_type; - static thread_local work_stealing_queue* local_work_queue; - static thread_local unsigned my_index; - - void worker_thread(unsigned my_index_) - { - my_index=my_index_; - local_work_queue=queues[my_index].get(); - while(!done) - { - run_pending_task(); - } + std::atomic_bool done; + thread_safe_queue pool_work_queue; + std::vector> queues; + std::vector threads; + join_threads joiner; + + static thread_local work_stealing_queue* local_work_queue; + static thread_local unsigned my_index; + + void worker_thread(unsigned my_index_) + { + my_index = my_index_; + local_work_queue = queues[my_index].get(); + while (!done) { + run_pending_task(); + } + } + + bool pop_task_from_local_queue(task_type& task) + { + return local_work_queue && local_work_queue->try_pop(task); + } + + bool pop_task_from_pool_queue(task_type& task) + { + return pool_work_queue.try_pop(task); + } + + bool pop_task_from_other_thread_queue(task_type& task) + { + for (unsigned i = 0; i < queues.size(); ++i) { + unsigned const index = (my_index + i + 1) % queues.size(); + if (queues[index]->try_steal(task)) { + return true; + } } - bool pop_task_from_local_queue(task_type& task) - { - return local_work_queue && local_work_queue->try_pop(task); - } - - bool pop_task_from_pool_queue(task_type& task) - { - return pool_work_queue.try_pop(task); - } - - bool pop_task_from_other_thread_queue(task_type& task) - { - for(unsigned i=0;itry_steal(task)) - { - return true; - } - } - - return false; - } + return false; + } public: - thread_pool(): - joiner(threads),done(false) - { - unsigned const thread_count=std::thread::hardware_concurrency(); + thread_pool() : joiner(threads), done(false) + { + unsigned const thread_count = std::thread::hardware_concurrency(); - try - { - for(unsigned i=0;i( - new work_stealing_queue)); - threads.push_back( - std::thread(&thread_pool::worker_thread,this,i)); - } - } - catch(...) - { - done=true; - throw; - } + try { + for (unsigned i = 0; i < thread_count; ++i) { + queues.push_back( + std::unique_ptr(new work_stealing_queue)); + threads.push_back(std::thread(&thread_pool::worker_thread, this, i)); + } } - - ~thread_pool() - { - done=true; + catch (...) { + done = true; + throw; } + } - template - using task_handle=std::unique_future; + ~thread_pool() { done = true; } - template - task_handle::type> submit( - FunctionType f) - { - typedef std::result_of::type result_type; - - std::packaged_task task(f); - task_handle res(task.get_future()); - if(local_work_queue) - { - local_work_queue->push(std::move(task)); - } - else - { - pool_work_queue.push(std::move(task)); - } - return res; - } + template + using task_handle = std::unique_future; - void run_pending_task() - { - task_type task; - if(pop_task_from_local_queue(task) || - pop_task_from_pool_queue(task) || - pop_task_from_other_thread_queue(task)) - { - task(); - } - else - { - std::this_thread::yield(); - } + template + task_handle::type> submit(FunctionType f) + { + typedef std::result_of::type result_type; + + std::packaged_task task(f); + task_handle res(task.get_future()); + if (local_work_queue) { + local_work_queue->push(std::move(task)); } + else { + pool_work_queue.push(std::move(task)); + } + return res; + } + + void run_pending_task() + { + task_type task; + if (pop_task_from_local_queue(task) || pop_task_from_pool_queue(task) || + pop_task_from_other_thread_queue(task)) { + task(); + } + else { + std::this_thread::yield(); + } + } }; diff --git a/source/listing_9.9.cpp b/source/listing_9.9.cpp index ffd7835..c704902 100644 --- a/source/listing_9.9.cpp +++ b/source/listing_9.9.cpp @@ -1,31 +1,29 @@ -class interrupt_flag -{ +class interrupt_flag { public: - void set(); - bool is_set() const; + void set(); + bool is_set() const; }; thread_local interrupt_flag this_thread_interrupt_flag; -class interruptible_thread -{ - std::thread internal_thread; - interrupt_flag* flag; +class interruptible_thread { + std::thread internal_thread; + interrupt_flag* flag; + public: - template - interruptible_thread(FunctionType f) - { - std::promise p; - internal_thread=std::thread([f,&p]{ - p.set_value(&this_thread_interrupt_flag); - f(); - }); - flag=p.get_future().get(); - } - void interrupt() - { - if(flag) - { - flag->set(); - } + template + interruptible_thread(FunctionType f) + { + std::promise p; + internal_thread = std::thread([f, &p] { + p.set_value(&this_thread_interrupt_flag); + f(); + }); + flag = p.get_future().get(); + } + void interrupt() + { + if (flag) { + flag->set(); } + } }; diff --git a/source/listing_a.1.cpp b/source/listing_a.1.cpp index 5a5956e..0ff9abf 100644 --- a/source/listing_a.1.cpp +++ b/source/listing_a.1.cpp @@ -1,23 +1,13 @@ -class X -{ +class X { private: - int* data; + int* data; + public: - X(): - data(new int[1000000]) - {} - ~X() - { - delete [] data; - } - X(const X& other): - data(new int[1000000]) - { - std::copy(other.data,other.data+1000000,data); - } - X(X&& other): - data(other.data) - { - other.data=nullptr; - } + X() : data(new int[1000000]) {} + ~X() { delete[] data; } + X(const X& other) : data(new int[1000000]) + { + std::copy(other.data, other.data + 1000000, data); + } + X(X&& other) : data(other.data) { other.data = nullptr; } }; diff --git a/source/listing_a.2.cpp b/source/listing_a.2.cpp index 647b826..101a51c 100644 --- a/source/listing_a.2.cpp +++ b/source/listing_a.2.cpp @@ -1,17 +1,15 @@ -class move_only -{ - std::unique_ptr data; +class move_only { + std::unique_ptr data; + public: - move_only(const move_only&) = delete; - move_only(move_only&& other): - data(std::move(other.data)) - {} - move_only& operator=(const move_only&) = delete; - move_only& operator=(move_only&& other) - { - data=std::move(other.data); - return *this; - } + move_only(const move_only&) = delete; + move_only(move_only&& other) : data(std::move(other.data)) {} + move_only& operator=(const move_only&) = delete; + move_only& operator =(move_only&& other) + { + data = std::move(other.data); + return *this; + } }; move_only m1; move_only m2(m1); diff --git a/source/listing_a.3.cpp b/source/listing_a.3.cpp index fd85c29..3e57c5a 100644 --- a/source/listing_a.3.cpp +++ b/source/listing_a.3.cpp @@ -1,23 +1,12 @@ -class CX -{ +class CX { private: - int a; - int b; + int a; + int b; + public: - CX() = default; - CX(int a_, int b_): - a(a_),b(b_) - {} - int get_a() const - { - return a; - } - int get_b() const - { - return b; - } - int foo() const - { - return a+b; - } + CX() = default; + CX(int a_, int b_) : a(a_), b(b_) {} + int get_a() const { return a; } + int get_b() const { return b; } + int foo() const { return a + b; } }; diff --git a/source/listing_a.4.cpp b/source/listing_a.4.cpp index 24a43f9..4a2c05f 100644 --- a/source/listing_a.4.cpp +++ b/source/listing_a.4.cpp @@ -1,8 +1,9 @@ std::condition_variable cond; bool data_ready; std::mutex m; -void wait_for_data() +void +wait_for_data() { - std::unique_lock lk(m); - cond.wait(lk,[]{return data_ready;}); + std::unique_lock lk(m); + cond.wait(lk, [] { return data_ready; }); } diff --git a/source/listing_c.1.cpp b/source/listing_c.1.cpp index bb66f44..bf42d42 100644 --- a/source/listing_c.1.cpp +++ b/source/listing_c.1.cpp @@ -2,49 +2,38 @@ #include #include #include - - - - -namespace messaging + namespace messaging { - struct message_base - { - virtual ~message_base() - {} - }; + struct message_base { + virtual ~message_base() {} + }; - template - struct wrapped_message: - message_base - { - Msg contents; - explicit wrapped_message(Msg const& contents_): - contents(contents_) - {} - }; + template + struct wrapped_message : message_base { + Msg contents; + explicit wrapped_message(Msg const& contents_) : contents(contents_) {} + }; - class queue + class queue { + std::mutex m; + std::condition_variable c; + message_base std::queue> q; + + public: + template + void push(T const& msg) { - std::mutex m; - std::condition_variable c; - message_base - std::queue > q; - public: - template - void push(T const& msg) - { - std::lock_guard lk(m); - q.push(std::make_shared >(msg)); - c.notify_all(); - } - std::shared_ptr wait_and_pop() - { - std::unique_lock lk(m); - c.wait(lk,[&]{return !q.empty();}); - auto res=q.front(); - q.pop(); - return res; - } - }; + std::lock_guard lk(m); + q.push(std::make_shared>(msg)); + c.notify_all(); + } + std::shared_ptr wait_and_pop() + { + std::unique_lock lk(m); + c.wait(lk, [&] { return !q.empty(); }); + auto res = q.front(); + q.pop(); + return res; + } + }; } diff --git a/source/listing_c.10.cpp b/source/listing_c.10.cpp index 3a3af51..4072c8c 100644 --- a/source/listing_c.10.cpp +++ b/source/listing_c.10.cpp @@ -1,51 +1,50 @@ -int main() +int +main() { - bank_machine bank; - interface_machine interface_hardware; - atm machine(bank.get_sender(),interface_hardware.get_sender()); - std::thread bank_thread(&bank_machine::run,&bank); - std::thread if_thread(&interface_machine::run,&interface_hardware); - std::thread atm_thread(&atm::run,&machine); - messaging::sender atmqueue(machine.get_sender()); - bool quit_pressed=false; - while(!quit_pressed) - { - char c=getchar(); - switch(c) - { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - atmqueue.send(digit_pressed(c)); - break; - case 'b': - atmqueue.send(balance_pressed()); - break; - case 'w': - atmqueue.send(withdraw_pressed(50)); - break; - case 'c': - atmqueue.send(cancel_pressed()); - break; - case 'q': - quit_pressed=true; - break; - case 'i': - atmqueue.send(card_inserted("acc1234")); - break; - } + bank_machine bank; + interface_machine interface_hardware; + atm machine(bank.get_sender(), interface_hardware.get_sender()); + std::thread bank_thread(&bank_machine::run, &bank); + std::thread if_thread(&interface_machine::run, &interface_hardware); + std::thread atm_thread(&atm::run, &machine); + messaging::sender atmqueue(machine.get_sender()); + bool quit_pressed = false; + while (!quit_pressed) { + char c = getchar(); + switch (c) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + atmqueue.send(digit_pressed(c)); + break; + case 'b': + atmqueue.send(balance_pressed()); + break; + case 'w': + atmqueue.send(withdraw_pressed(50)); + break; + case 'c': + atmqueue.send(cancel_pressed()); + break; + case 'q': + quit_pressed = true; + break; + case 'i': + atmqueue.send(card_inserted("acc1234")); + break; } - bank.done(); - machine.done(); - interface_hardware.done(); - atm_thread.join(); - bank_thread.join(); - if_thread.join(); + } + bank.done(); + machine.done(); + interface_hardware.done(); + atm_thread.join(); + bank_thread.join(); + if_thread.join(); } diff --git a/source/listing_c.2.cpp b/source/listing_c.2.cpp index 822b509..8c80177 100644 --- a/source/listing_c.2.cpp +++ b/source/listing_c.2.cpp @@ -1,22 +1,16 @@ -namespace messaging -{ - class sender - { - queue*q; - public: - sender(): - q(nullptr) - {} - explicit sender(queue*q_): - q(q_) - {} - template - void send(Message const& msg) - { - if(q) - { - q->push(msg); - } - } - }; -} +namespace messaging { +class sender { + queue* q; + +public: + sender() : q(nullptr) {} + explicit sender(queue* q_) : q(q_) {} + template + void send(Message const& msg) + { + if (q) { + q->push(msg); + } + } +}; +} // namespace messaging diff --git a/source/listing_c.3.cpp b/source/listing_c.3.cpp index 6396f50..ee3d9ca 100644 --- a/source/listing_c.3.cpp +++ b/source/listing_c.3.cpp @@ -1,16 +1,9 @@ -namespace messaging -{ - class receiver - { - queue q; - public: - operator sender() - { - return sender(&q); - } - dispatcher wait() - { - return dispatcher(&q); - } - }; -} +namespace messaging { +class receiver { + queue q; + +public: + operator sender() { return sender(&q); } + dispatcher wait() { return dispatcher(&q); } +}; +} // namespace messaging diff --git a/source/listing_c.4.cpp b/source/listing_c.4.cpp index 2ca84a1..c9165df 100644 --- a/source/listing_c.4.cpp +++ b/source/listing_c.4.cpp @@ -1,65 +1,53 @@ -namespace messaging -{ - class close_queue - {}; +namespace messaging { +class close_queue { +}; - class dispatcher - { - queue* q; - bool chained; +class dispatcher { + queue* q; + bool chained; - dispatcher(dispatcher const&)=delete; - dispatcher& operator=(dispatcher const&)=delete; + dispatcher(dispatcher const&) = delete; + dispatcher& operator=(dispatcher const&) = delete; - template< - typename Dispatcher, - typename Msg, - typename Func> - friend class TemplateDispatcher; + template + friend class TemplateDispatcher; - void wait_and_dispatch() - { - for(;;) - { - auto msg=q->wait_and_pop(); - dispatch(msg); - } - } + void wait_and_dispatch() + { + for (;;) { + auto msg = q->wait_and_pop(); + dispatch(msg); + } + } - bool dispatch( - std::shared_ptr const& msg) - { - if(dynamic_cast*>(msg.get())) - { - throw close_queue(); - } - return false; - } - public: - dispatcher(dispatcher&& other): - q(other.q),chained(other.chained) - { - other.chained=true; - } + bool dispatch(std::shared_ptr const& msg) + { + if (dynamic_cast*>(msg.get())) { + throw close_queue(); + } + return false; + } - explicit dispatcher(queue* q_): - q(q_),chained(false) - {} +public: + dispatcher(dispatcher&& other) : q(other.q), chained(other.chained) + { + other.chained = true; + } - template - TemplateDispatcher - handle(Func&& f) - { - return TemplateDispatcher( - q,this,std::forward(f)); - } + explicit dispatcher(queue* q_) : q(q_), chained(false) {} - ~dispatcher() noexcept(false) - { - if(!chained) - { - wait_and_dispatch(); - } - } - }; -} + template + TemplateDispatcher handle(Func&& f) + { + return TemplateDispatcher( + q, this, std::forward(f)); + } + + ~dispatcher() noexcept(false) + { + if (!chained) { + wait_and_dispatch(); + } + } +}; +} // namespace messaging diff --git a/source/listing_c.5.cpp b/source/listing_c.5.cpp index 41fa481..9920201 100644 --- a/source/listing_c.5.cpp +++ b/source/listing_c.5.cpp @@ -1,71 +1,67 @@ -namespace messaging -{ - template - class TemplateDispatcher - { - queue* q; - PreviousDispatcher* prev; - Func f; - bool chained; +namespace messaging { +template +class TemplateDispatcher { + queue* q; + PreviousDispatcher* prev; + Func f; + bool chained; - TemplateDispatcher(TemplateDispatcher const&)=delete; - TemplateDispatcher& operator=(TemplateDispatcher const&)=delete; + TemplateDispatcher(TemplateDispatcher const&) = delete; + TemplateDispatcher& operator=(TemplateDispatcher const&) = delete; - template - friend class TemplateDispatcher; + template + friend class TemplateDispatcher; - void wait_and_dispatch() - { - for(;;) - { - auto msg=q->wait_and_pop(); - if(dispatch(msg)) - break; - } - } + void wait_and_dispatch() + { + for (;;) { + auto msg = q->wait_and_pop(); + if (dispatch(msg)) + break; + } + } - bool dispatch(std::shared_ptr const& msg) - { - if(wrapped_message* wrapper= - dynamic_cast*>(msg.get())) - { - f(wrapper->contents); - return true; - } - else - { - return prev->dispatch(msg); - } - } - public: - TemplateDispatcher(TemplateDispatcher&& other): - q(other.q),prev(other.prev),f(std::move(other.f)), - chained(other.chained) - { - other.chained=true; - } + bool dispatch(std::shared_ptr const& msg) + { + if (wrapped_message* wrapper = + dynamic_cast*>(msg.get())) { + f(wrapper->contents); + return true; + } + else { + return prev->dispatch(msg); + } + } - TemplateDispatcher(queue* q_,PreviousDispatcher* prev_,Func&& f_): - q(q_),prev(prev_),f(std::forward(f_)),chained(false) - { - prev_->chained=true; - } +public: + TemplateDispatcher(TemplateDispatcher&& other) + : q(other.q), + prev(other.prev), + f(std::move(other.f)), + chained(other.chained) + { + other.chained = true; + } - template - TemplateDispatcher - handle(OtherFunc&& of) - { - return TemplateDispatcher< - TemplateDispatcher,OtherMsg,OtherFunc>( - q,this,std::forward(of)); - } + TemplateDispatcher(queue* q_, PreviousDispatcher* prev_, Func&& f_) + : q(q_), prev(prev_), f(std::forward(f_)), chained(false) + { + prev_->chained = true; + } - ~TemplateDispatcher() noexcept(false) - { - if(!chained) - { - wait_and_dispatch(); - } - } - }; -} + template + TemplateDispatcher handle( + OtherFunc&& of) + { + return TemplateDispatcher( + q, this, std::forward(of)); + } + + ~TemplateDispatcher() noexcept(false) + { + if (!chained) { + wait_and_dispatch(); + } + } +}; +} // namespace messaging diff --git a/source/listing_c.6.cpp b/source/listing_c.6.cpp index 14d05fa..35e718f 100644 --- a/source/listing_c.6.cpp +++ b/source/listing_c.6.cpp @@ -1,118 +1,98 @@ -struct withdraw -{ - std::string account; - unsigned amount; - mutable messaging::sender atm_queue; - withdraw(std::string const& account_, - unsigned amount_, - messaging::sender atm_queue_): - account(account_),amount(amount_), - atm_queue(atm_queue_) - {} +struct withdraw { + std::string account; + unsigned amount; + mutable messaging::sender atm_queue; + withdraw(std::string const& account_, + unsigned amount_, + messaging::sender atm_queue_) + : account(account_), amount(amount_), atm_queue(atm_queue_) + { + } }; -struct withdraw_ok -{}; -struct withdraw_denied -{}; -struct cancel_withdrawal -{ - std::string account; - unsigned amount; - cancel_withdrawal(std::string const& account_, - unsigned amount_): - account(account_),amount(amount_) - {} +struct withdraw_ok { }; -struct withdrawal_processed -{ - std::string account; - unsigned amount; - withdrawal_processed(std::string const& account_, - unsigned amount_): - account(account_),amount(amount_) - {} +struct withdraw_denied { }; -struct card_inserted -{ - std::string account; - explicit card_inserted(std::string const& account_): - account(account_) - {} +struct cancel_withdrawal { + std::string account; + unsigned amount; + cancel_withdrawal(std::string const& account_, unsigned amount_) + : account(account_), amount(amount_) + { + } }; -struct digit_pressed -{ - char digit; - explicit digit_pressed(char digit_): - digit(digit_) - {} +struct withdrawal_processed { + std::string account; + unsigned amount; + withdrawal_processed(std::string const& account_, unsigned amount_) + : account(account_), amount(amount_) + { + } }; -struct clear_last_pressed -{}; -struct eject_card -{}; -struct withdraw_pressed -{ - unsigned amount; - explicit withdraw_pressed(unsigned amount_): - amount(amount_) - {} +struct card_inserted { + std::string account; + explicit card_inserted(std::string const& account_) : account(account_) {} }; -struct cancel_pressed -{}; -struct issue_money -{ - unsigned amount; - issue_money(unsigned amount_): - amount(amount_) - {} +struct digit_pressed { + char digit; + explicit digit_pressed(char digit_) : digit(digit_) {} }; -struct verify_pin -{ - std::string account; - std::string pin; - mutable messaging::sender atm_queue; - verify_pin(std::string const& account_,std::string const& pin_, - messaging::sender atm_queue_): - account(account_),pin(pin_),atm_queue(atm_queue_) - {} +struct clear_last_pressed { }; -struct pin_verified -{}; -struct pin_incorrect -{}; -struct display_enter_pin -{}; -struct display_enter_card -{}; -struct display_insufficient_funds -{}; -struct display_withdrawal_cancelled -{}; -struct display_pin_incorrect_message -{}; -struct display_withdrawal_options -{}; -struct get_balance -{ - std::string account; - mutable messaging::sender atm_queue; - get_balance(std::string const& account_,messaging::sender atm_queue_): - account(account_),atm_queue(atm_queue_) - {} +struct eject_card { }; -struct balance -{ - unsigned amount; - explicit balance(unsigned amount_): - amount(amount_) - {} +struct withdraw_pressed { + unsigned amount; + explicit withdraw_pressed(unsigned amount_) : amount(amount_) {} }; -struct display_balance -{ - unsigned amount; - explicit display_balance(unsigned amount_): - amount(amount_) - {} +struct cancel_pressed { +}; +struct issue_money { + unsigned amount; + issue_money(unsigned amount_) : amount(amount_) {} +}; +struct verify_pin { + std::string account; + std::string pin; + mutable messaging::sender atm_queue; + verify_pin(std::string const& account_, + std::string const& pin_, + messaging::sender atm_queue_) + : account(account_), pin(pin_), atm_queue(atm_queue_) + { + } +}; +struct pin_verified { +}; +struct pin_incorrect { +}; +struct display_enter_pin { +}; +struct display_enter_card { +}; +struct display_insufficient_funds { +}; +struct display_withdrawal_cancelled { +}; +struct display_pin_incorrect_message { +}; +struct display_withdrawal_options { +}; +struct get_balance { + std::string account; + mutable messaging::sender atm_queue; + get_balance(std::string const& account_, messaging::sender atm_queue_) + : account(account_), atm_queue(atm_queue_) + { + } +}; +struct balance { + unsigned amount; + explicit balance(unsigned amount_) : amount(amount_) {} +}; +struct display_balance { + unsigned amount; + explicit display_balance(unsigned amount_) : amount(amount_) {} +}; +struct balance_pressed { }; -struct balance_pressed -{}; diff --git a/source/listing_c.7.cpp b/source/listing_c.7.cpp index 6ce0508..5c8d15d 100644 --- a/source/listing_c.7.cpp +++ b/source/listing_c.7.cpp @@ -1,187 +1,120 @@ -class atm -{ - messaging::receiver incoming; - messaging::sender bank; - messaging::sender interface_hardware; - void (atm::*state)(); - std::string account; - unsigned withdrawal_amount; - std::string pin; - void process_withdrawal() - { - incoming.wait() - .handle( - [&](withdraw_ok const& msg) - { - interface_hardware.send( - issue_money(withdrawal_amount)); - bank.send( - withdrawal_processed(account,withdrawal_amount)); - state=&atm::done_processing; - } - ) - .handle( - [&](withdraw_denied const& msg) - { - interface_hardware.send(display_insufficient_funds()); - state=&atm::done_processing; - } - ) - .handle( - [&](cancel_pressed const& msg) - { - bank.send( - cancel_withdrawal(account,withdrawal_amount)); - interface_hardware.send( - display_withdrawal_cancelled()); - state=&atm::done_processing; - } - ); - } - void process_balance() - { - incoming.wait() - .handle( - [&](balance const& msg) - { - interface_hardware.send(display_balance(msg.amount)); - state=&atm::wait_for_action; - } - ) - .handle( - [&](cancel_pressed const& msg) - { - state=&atm::done_processing; - } - ); - } - void wait_for_action() - { - interface_hardware.send(display_withdrawal_options()); - incoming.wait() - .handle( - [&](withdraw_pressed const& msg) - { - withdrawal_amount=msg.amount; - bank.send(withdraw(account,msg.amount,incoming)); - state=&atm::process_withdrawal; - } - ) - .handle( - [&](balance_pressed const& msg) - { - bank.send(get_balance(account,incoming)); - state=&atm::process_balance; - } - ) - .handle( - [&](cancel_pressed const& msg) - { - state=&atm::done_processing; - } - ); - } - void verifying_pin() - { - incoming.wait() - .handle( - [&](pin_verified const& msg) - { - state=&atm::wait_for_action; - } - ) - .handle( - [&](pin_incorrect const& msg) - { - interface_hardware.send( - display_pin_incorrect_message()); - state=&atm::done_processing; - } - ) - .handle( - [&](cancel_pressed const& msg) - { - state=&atm::done_processing; - } - ); - } - void getting_pin() - { - incoming.wait() - .handle( - [&](digit_pressed const& msg) - { - unsigned const pin_length=4; - pin+=msg.digit; - if(pin.length()==pin_length) - { - bank.send(verify_pin(account,pin,incoming)); - state=&atm::verifying_pin; - } - } - ) - .handle( - [&](clear_last_pressed const& msg) - { - if(!pin.empty()) - { - pin.pop_back(); - } - } - ) - .handle( - [&](cancel_pressed const& msg) - { - state=&atm::done_processing; - } - ); - } - void waiting_for_card() - { - interface_hardware.send(display_enter_card()); - incoming.wait() - .handle( - [&](card_inserted const& msg) - { - account=msg.account; - pin=""; - interface_hardware.send(display_enter_pin()); - state=&atm::getting_pin; - } - ); - } - void done_processing() - { - interface_hardware.send(eject_card()); - state=&atm::waiting_for_card; - } - atm(atm const&)=delete; - atm& operator=(atm const&)=delete; +class atm { + messaging::receiver incoming; + messaging::sender bank; + messaging::sender interface_hardware; + void (atm::*state)(); + std::string account; + unsigned withdrawal_amount; + std::string pin; + void process_withdrawal() + { + incoming.wait() + .handle([&](withdraw_ok const& msg) { + interface_hardware.send(issue_money(withdrawal_amount)); + bank.send(withdrawal_processed(account, withdrawal_amount)); + state = &atm::done_processing; + }) + .handle([&](withdraw_denied const& msg) { + interface_hardware.send(display_insufficient_funds()); + state = &atm::done_processing; + }) + .handle([&](cancel_pressed const& msg) { + bank.send(cancel_withdrawal(account, withdrawal_amount)); + interface_hardware.send(display_withdrawal_cancelled()); + state = &atm::done_processing; + }); + } + void process_balance() + { + incoming.wait() + .handle([&](balance const& msg) { + interface_hardware.send(display_balance(msg.amount)); + state = &atm::wait_for_action; + }) + .handle( + [&](cancel_pressed const& msg) { state = &atm::done_processing; }); + } + void wait_for_action() + { + interface_hardware.send(display_withdrawal_options()); + incoming.wait() + .handle([&](withdraw_pressed const& msg) { + withdrawal_amount = msg.amount; + bank.send(withdraw(account, msg.amount, incoming)); + state = &atm::process_withdrawal; + }) + .handle([&](balance_pressed const& msg) { + bank.send(get_balance(account, incoming)); + state = &atm::process_balance; + }) + .handle( + [&](cancel_pressed const& msg) { state = &atm::done_processing; }); + } + void verifying_pin() + { + incoming.wait() + .handle( + [&](pin_verified const& msg) { state = &atm::wait_for_action; }) + .handle([&](pin_incorrect const& msg) { + interface_hardware.send(display_pin_incorrect_message()); + state = &atm::done_processing; + }) + .handle( + [&](cancel_pressed const& msg) { state = &atm::done_processing; }); + } + void getting_pin() + { + incoming.wait() + .handle([&](digit_pressed const& msg) { + unsigned const pin_length = 4; + pin += msg.digit; + if (pin.length() == pin_length) { + bank.send(verify_pin(account, pin, incoming)); + state = &atm::verifying_pin; + } + }) + .handle([&](clear_last_pressed const& msg) { + if (!pin.empty()) { + pin.pop_back(); + } + }) + .handle( + [&](cancel_pressed const& msg) { state = &atm::done_processing; }); + } + void waiting_for_card() + { + interface_hardware.send(display_enter_card()); + incoming.wait().handle([&](card_inserted const& msg) { + account = msg.account; + pin = ""; + interface_hardware.send(display_enter_pin()); + state = &atm::getting_pin; + }); + } + void done_processing() + { + interface_hardware.send(eject_card()); + state = &atm::waiting_for_card; + } + atm(atm const&) = delete; + atm& operator=(atm const&) = delete; + public: - atm(messaging::sender bank_, - messaging::sender interface_hardware_): - bank(bank_),interface_hardware(interface_hardware_) - {} - void done() - { - get_sender().send(messaging::close_queue()); + atm(messaging::sender bank_, messaging::sender interface_hardware_) + : bank(bank_), interface_hardware(interface_hardware_) + { + } + void done() { get_sender().send(messaging::close_queue()); } + void run() + { + state = &atm::waiting_for_card; + try { + for (;;) { + (this->*state)(); + } } - void run() - { - state=&atm::waiting_for_card; - try - { - for(;;) - { - (this->*state)(); - } - } - catch(messaging::close_queue const&) - { - } - } - messaging::sender get_sender() - { - return incoming; + catch (messaging::close_queue const&) { } + } + messaging::sender get_sender() { return incoming; } }; diff --git a/source/listing_c.8.cpp b/source/listing_c.8.cpp index a8e5566..2a64f02 100644 --- a/source/listing_c.8.cpp +++ b/source/listing_c.8.cpp @@ -1,73 +1,42 @@ -class bank_machine -{ - messaging::receiver incoming; - unsigned balance; +class bank_machine { + messaging::receiver incoming; + unsigned balance; + public: - bank_machine(): - balance(199) - {} - void done() - { - get_sender().send(messaging::close_queue()); + bank_machine() : balance(199) {} + void done() { get_sender().send(messaging::close_queue()); } + void run() + { + try { + for (;;) { + incoming.wait() + .handle([&](verify_pin const& msg) { + if (msg.pin == "1937") { + msg.atm_queue.send(pin_verified()); + } + else { + msg.atm_queue.send(pin_incorrect()); + } + }) + .handle([&](withdraw const& msg) { + if (balance >= msg.amount) { + msg.atm_queue.send(withdraw_ok()); + balance -= msg.amount; + } + else { + msg.atm_queue.send(withdraw_denied()); + } + }) + .handle([&](get_balance const& msg) { + msg.atm_queue.send(::balance(balance)); + }) + .handle( + [&](withdrawal_processed const& msg) {}) + .handle([&](cancel_withdrawal const& msg) {}); + } } - void run() - { - try - { - for(;;) - { - incoming.wait() - .handle( - [&](verify_pin const& msg) - { - if(msg.pin=="1937") - { - msg.atm_queue.send(pin_verified()); - } - else - { - msg.atm_queue.send(pin_incorrect()); - } - } - ) - .handle( - [&](withdraw const& msg) - { - if(balance>=msg.amount) - { - msg.atm_queue.send(withdraw_ok()); - balance-=msg.amount; - } - else - { - msg.atm_queue.send(withdraw_denied()); - } - } - ) - .handle( - [&](get_balance const& msg) - { - msg.atm_queue.send(::balance(balance)); - } - ) - .handle( - [&](withdrawal_processed const& msg) - { - } - ) - .handle( - [&](cancel_withdrawal const& msg) - { - } - ); - } - } - catch(messaging::close_queue const&) - { - } - } - messaging::sender get_sender() - { - return incoming; + catch (messaging::close_queue const&) { } + } + messaging::sender get_sender() { return incoming; } }; diff --git a/source/listing_c.9.cpp b/source/listing_c.9.cpp index 3d1a24a..792bfd9 100644 --- a/source/listing_c.9.cpp +++ b/source/listing_c.9.cpp @@ -1,117 +1,78 @@ -class interface_machine -{ - messaging::receiver incoming; +class interface_machine { + messaging::receiver incoming; + public: - void done() - { - get_sender().send(messaging::close_queue()); + void done() { get_sender().send(messaging::close_queue()); } + void run() + { + try { + for (;;) { + incoming.wait() + .handle([&](issue_money const& msg) { + { + std::lock_guard lk(iom); + std::cout << "Issuing " << msg.amount << std::endl; + } + }) + .handle( + [&](display_insufficient_funds const& msg) { + { + std::lock_guard lk(iom); + std::cout << "Insufficient funds" << std::endl; + } + }) + .handle([&](display_enter_pin const& msg) { + { + std::lock_guard lk(iom); + std::cout << "Please enter your PIN (0-9)" << std::endl; + } + }) + .handle([&](display_enter_card const& msg) { + { + std::lock_guard lk(iom); + std::cout << "Please enter your card (I)" << std::endl; + } + }) + .handle([&](display_balance const& msg) { + { + std::lock_guard lk(iom); + std::cout << "The balance of your account is " << msg.amount + << std::endl; + } + }) + .handle( + [&](display_withdrawal_options const& msg) { + { + std::lock_guard lk(iom); + std::cout << "Withdraw 50? (w)" << std::endl; + std::cout << "Display Balance? (b)" << std::endl; + std::cout << "Cancel? (c)" << std::endl; + } + }) + .handle( + [&](display_withdrawal_cancelled const& msg) { + { + std::lock_guard lk(iom); + std::cout << "Withdrawal cancelled" << std::endl; + } + }) + .handle( + [&](display_pin_incorrect_message const& msg) { + { + std::lock_guard lk(iom); + std::cout << "PIN incorrect" << std::endl; + } + }) + .handle([&](eject_card const& msg) { + { + std::lock_guard lk(iom); + std::cout << "Ejecting card" << std::endl; + } + }); + } } - void run() - { - try - { - for(;;) - { - incoming.wait() - .handle( - [&](issue_money const& msg) - { - { - std::lock_guard lk(iom); - std::cout<<"Issuing " - <( - [&](display_insufficient_funds const& msg) - { - { - std::lock_guard lk(iom); - std::cout<<"Insufficient funds"<( - [&](display_enter_pin const& msg) - { - { - std::lock_guard lk(iom); - std::cout - <<"Please enter your PIN (0-9)" - <( - [&](display_enter_card const& msg) - { - { - std::lock_guard lk(iom); - std::cout<<"Please enter your card (I)" - <( - [&](display_balance const& msg) - { - { - std::lock_guard lk(iom); - std::cout - <<"The balance of your account is " - <( - [&](display_withdrawal_options const& msg) - { - { - std::lock_guard lk(iom); - std::cout<<"Withdraw 50? (w)"<( - [&](display_withdrawal_cancelled const& msg) - { - { - std::lock_guard lk(iom); - std::cout<<"Withdrawal cancelled" - <( - [&](display_pin_incorrect_message const& msg) - { - { - std::lock_guard lk(iom); - std::cout<<"PIN incorrect"<( - [&](eject_card const& msg) - { - { - std::lock_guard lk(iom); - std::cout<<"Ejecting card"<