From 809451045e1609c8dc6ee431115bbfe99f7caae3 Mon Sep 17 00:00:00 2001 From: Bo Wang Date: Tue, 1 Nov 2016 00:18:21 -0400 Subject: [PATCH] chapter 6 code --- ch6/Makefile | 34 ++++++++++ ch6/list.cpp | 126 ++++++++++++++++++++++++++++++++++++ ch6/lookuptable.cpp | 133 ++++++++++++++++++++++++++++++++++++++ ch6/queue.cpp | 112 ++++++++++++++++++++++++++++++++ ch6/queuelist.cpp | 94 +++++++++++++++++++++++++++ ch6/queuelist2.cpp | 154 ++++++++++++++++++++++++++++++++++++++++++++ ch6/stack.cpp | 62 ++++++++++++++++++ 7 files changed, 715 insertions(+) create mode 100644 ch6/Makefile create mode 100644 ch6/list.cpp create mode 100644 ch6/lookuptable.cpp create mode 100644 ch6/queue.cpp create mode 100644 ch6/queuelist.cpp create mode 100644 ch6/queuelist2.cpp create mode 100644 ch6/stack.cpp diff --git a/ch6/Makefile b/ch6/Makefile new file mode 100644 index 0000000..afc03a3 --- /dev/null +++ b/ch6/Makefile @@ -0,0 +1,34 @@ +CPP = g++ +CPPFLAGS = -g -std=c++0x +OFLAG = -o +.SUFFIXES : .o .cpp .c +.cpp.o : + $(CPP) $(CPPFLAGS) -c $< +.c.o : + $(CPP) $(CPPFLAGS) -c $< + +PROGS = stack queue queuelist queuelist2 list + +all: $(PROGS) + +stack: stack.o + $(CPP) $(OFLAG) stack stack.o -lpthread + +queue: queue.o + $(CPP) $(OFLAG) queue queue.o -lpthread + +queuelist: queuelist.o + $(CPP) $(OFLAG) queuelist queuelist.o -lpthread + +queuelist2: queuelist2.o + $(CPP) $(OFLAG) queuelist2 queuelist2.o -lpthread + +lookuptable: lookuptable.o + $(CPP) $(OFLAG) lookuptable lookuptable.o -lpthread + +list: list.o + $(CPP) $(OFLAG) list list.o -lpthread + +clean: + rm -f ${PROGS} *.o + diff --git a/ch6/list.cpp b/ch6/list.cpp new file mode 100644 index 0000000..8f8a0b4 --- /dev/null +++ b/ch6/list.cpp @@ -0,0 +1,126 @@ +#include +#include +#include +#include + +template +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 head; + + 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); + } + } + + 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); + } + } + } +}; + +void push(list* l) +{ + for (int i = 0; i < 10; ++i) { + printf("pushing %d\n", i); + l->push_front(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; +} + diff --git a/ch6/lookuptable.cpp b/ch6/lookuptable.cpp new file mode 100644 index 0000000..fe0e672 --- /dev/null +++ b/ch6/lookuptable.cpp @@ -0,0 +1,133 @@ +#include +#include +#include +#include +#include +#include +#include + +template > +class lookup_table +{ + private: + 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 + { + 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]; + } + + 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() +{ + 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 new file mode 100644 index 0000000..d2cd772 --- /dev/null +++ b/ch6/queue.cpp @@ -0,0 +1,112 @@ +#include +#include +#include +#include +#include +#include +#include + +template +class queue +{ + private: + mutable std::mutex mut; + std::queue > data_queue; + std::condition_variable data_cond; + + public: + 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(); + } + + 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; + } + + 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(); + } +}; + +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); + } +} + +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; +} + diff --git a/ch6/queuelist.cpp b/ch6/queuelist.cpp new file mode 100644 index 0000000..9a23bfa --- /dev/null +++ b/ch6/queuelist.cpp @@ -0,0 +1,94 @@ +#include +#include +#include +#include +#include + +template +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; + + 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; + } + + 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 = 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(queue* q) +{ + 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; + } +} + +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 new file mode 100644 index 0000000..52c6ee5 --- /dev/null +++ b/ch6/queuelist2.cpp @@ -0,0 +1,154 @@ +#include +#include +#include +#include +#include +#include + +template +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; + + 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 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 push(queue* q) +{ + for (int i = 0; i < 10; ++i) { + printf("pushing %d\n", i); + q->push(i); + } +} + +void pop(queue* q) +{ + int i = 0; + for (int i = 0; i < 10; ++i) { + printf("poping %d\n", *q->wait_and_pop()); + } +} + +int main() +{ + 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 new file mode 100644 index 0000000..e00feb1 --- /dev/null +++ b/ch6/stack.cpp @@ -0,0 +1,62 @@ +#include +#include +#include +#include +#include +#include + +template +class stack +{ + private: + std::stack data; + mutable std::mutex m; + + public: + stack(){} + + stack(const stack& other) + { + std::lock_guard lock(other.m); + data = other.data; + } + + stack& operator=(const 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 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(); + } + + bool empty() const + { + std::lock_guard lock(m); + return data.empty(); + } +}; + +int main() +{ + stack s; + s.push(1); + std::cout << *s.pop() << std::endl; +} +