Combining Listing 6.1 and Listing 8.1 we get the following runtime error:
|
#include <exception> |
|
#include <stack> |
|
#include <mutex> |
|
#include <memory> |
|
|
|
struct empty_stack: std::exception |
|
{ |
|
const char* what() const throw() |
|
{ |
|
return "empty stack"; |
|
} |
|
}; |
|
|
|
template<typename T> |
|
class threadsafe_stack |
|
{ |
|
private: |
|
std::stack<T> data; |
|
mutable std::mutex m; |
|
public: |
|
threadsafe_stack(){} |
|
threadsafe_stack(const threadsafe_stack& other) |
|
{ |
|
std::lock_guard<std::mutex> lock(other.m); |
|
data=other.data; |
|
} |
|
threadsafe_stack& operator=(const threadsafe_stack&) = delete; |
|
|
|
void push(T new_value) |
|
{ |
|
std::lock_guard<std::mutex> lock(m); |
|
data.push(std::move(new_value)); |
|
} |
|
std::shared_ptr<T> pop() |
|
{ |
|
std::lock_guard<std::mutex> lock(m); |
|
if(data.empty()) throw empty_stack(); |
|
std::shared_ptr<T> const res( |
|
std::make_shared<T>(std::move(data.top()))); |
|
data.pop(); |
|
return res; |
|
} |
|
void pop(T& value) |
|
{ |
|
std::lock_guard<std::mutex> lock(m); |
|
if(data.empty()) throw empty_stack(); |
|
value=std::move(data.top()); |
|
data.pop(); |
|
} |
|
bool empty() const |
|
{ |
|
std::lock_guard<std::mutex> lock(m); |
|
return data.empty(); |
|
} |
|
}; |
|
#include <thread> |
|
#include <vector> |
|
#include <future> |
|
#include <list> |
|
template<typename T> |
|
struct sorter |
|
{ |
|
struct chunk_to_sort |
|
{ |
|
std::list<T> data; |
|
std::promise<std::list<T> > promise; |
|
}; |
|
|
|
thread_safe_stack<chunk_to_sort> chunks; |
|
std::vector<std::thread> threads; |
|
unsigned const max_thread_count; |
|
std::atomic<bool> end_of_data; |
|
|
|
sorter(): |
|
max_thread_count(std::thread::hardware_concurrency()-1), |
|
end_of_data(false) |
|
{} |
|
|
|
~sorter() |
|
{ |
|
end_of_data=true; |
|
for(unsigned i=0;i<threads.size();++i) |
|
{ |
|
threads[i].join(); |
|
} |
|
} |
|
|
|
void try_sort_chunk() |
|
{ |
|
boost::shared_ptr<chunk_to_sort > chunk=chunks.pop(); |
|
if(chunk) |
|
{ |
|
sort_chunk(chunk); |
|
} |
|
} |
|
|
|
std::list<T> do_sort(std::list<T>& chunk_data) |
|
{ |
|
if(chunk_data.empty()) |
|
{ |
|
return chunk_data; |
|
} |
|
|
|
std::list<T> result; |
|
result.splice(result.begin(),chunk_data,chunk_data.begin()); |
|
T const& partition_val=*result.begin(); |
|
|
|
typename std::list<T>::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<std::list<T> > 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<T>::sort_thread,this)); |
|
} |
|
|
|
std::list<T> 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; |
|
} |
|
|
|
void sort_chunk(boost::shared_ptr<chunk_to_sort > 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<typename T> |
|
std::list<T> parallel_quick_sort(std::list<T> input) |
|
{ |
|
if(input.empty()) |
|
{ |
|
return input; |
|
} |
|
sorter<T> s; |
|
return s.do_sort(input); |
|
} |
libc++abi: terminating due to uncaught exception of type empty_stack: empty stack
Message from debugger: killed
Program ended with exit code: 9
This is after making a few amendments to allow the code to compile.
// thread_safe_stack<chunk_to_sort> chunks;
threadsafe_stack<chunk_to_sort> chunks;
// std::shared_ptr<T> pop()
boost::shared_ptr<T> pop()
{
std::lock_guard<std::mutex> lock(m);
if(data.empty()) throw empty_stack();
// std::shared_ptr<T> const res( std::make_shared<T>(std::move(data.top())));
boost::shared_ptr<T> const res(new T(std::move(data.top())));
data.pop();
return res;
}
The same error shows with both boost::shared_ptr<T> and std::shared_ptr<T>.
I will link a PR once I find a solution.
On a personal note, please...please test your code...
Whilst I appreciate the following from page 255...
"As with most of the examples, this is intended to demonstrate an idea rather than being production-ready code."
, ...it's extremely unhelpful as a reader to be exposed to code that either doesn't compile, run, or exhibits data races / undefined behaviour on a frequent basis.
It would also be nice if this repo could be rejigged to include a combination of listing excerpts (that focus on the changes) and full listings (that demonstrate functionality)
Combining Listing 6.1 and Listing 8.1 we get the following runtime error:
ccia_code_samples/listings/listing_6.1.cpp
Lines 1 to 55 in 6e7ae1d
ccia_code_samples/listings/listing_8.1.cpp
Lines 1 to 106 in 6e7ae1d
This is after making a few amendments to allow the code to compile.
// thread_safe_stack<chunk_to_sort> chunks; threadsafe_stack<chunk_to_sort> chunks;The same error shows with both
boost::shared_ptr<T>andstd::shared_ptr<T>.I will link a PR once I find a solution.
On a personal note, please...please test your code...
Whilst I appreciate the following from page 255...
, ...it's extremely unhelpful as a reader to be exposed to code that either doesn't compile, run, or exhibits data races / undefined behaviour on a frequent basis.
It would also be nice if this repo could be rejigged to include a combination of listing excerpts (that focus on the changes) and full listings (that demonstrate functionality)