chapter 6 code

This commit is contained in:
Bo Wang
2016-11-01 00:18:21 -04:00
parent 39e08c0cfc
commit 809451045e
7 changed files with 715 additions and 0 deletions

34
ch6/Makefile Normal file
View File

@@ -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

126
ch6/list.cpp Normal file
View File

@@ -0,0 +1,126 @@
#include <iostream>
#include <thread>
#include <memory>
#include <cstdio>
template <typename T>
class list
{
struct node
{
std::mutex m;
std::shared_ptr<T> data;
std::unique_ptr<node> next;
node()
: next()
{}
node(T const& value)
: data(std::make_shared<T>(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<node> new_node(new node(value));
std::lock_guard<std::mutex> lk(head.m);
new_node->next = std::move(head.next);
head.next = std::move(new_node);
}
template <typename Function>
void for_each(Function f)
{
node* current = &head;
std::unique_lock<std::mutex> lk(head.m);
while (node* const next = current->next.get())
{
std::unique_lock<std::mutex> next_lk(next->m);
lk.unlock();
f(*next->data);
current = next;
lk = std::move(next_lk);
}
}
template <typename Predicate>
std::shared_ptr<T> find_first_of(Predicate p)
{
node *current = &head;
std::unique_lock<std::mutex> lk(head.m);
while (node* const next = current->next.get())
{
std::unique_lock<std::mutex> next_lk(next->m);
lk.unlock();
if (p(*next->data))
{
return next->data;
}
current = next;
lk = std::move(next_lk);
}
return std::shared_ptr<T>();
}
template <typename Predicate>
void remove_if(Predicate p)
{
node *current = &head;
std::unique_lock<std::mutex> lk(head.m);
while (node* const next = current->next.get())
{
std::unique_lock<std::mutex> next_lk(next->m);
if (p(*next->data))
{
std::unique_ptr<node> 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<int>* 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<int> l;
std::thread t(push,&l);
sleep(1);
l.for_each(visit);
t.join();
return 0;
}

133
ch6/lookuptable.cpp Normal file
View File

@@ -0,0 +1,133 @@
#include <iostream>
#include <string>
#include <thread>
#include <boost/thread/shared_mutex.hpp>
#include <memory>
#include <list>
#include <vector>
template <typename Key, typename Value, typename Hash=std::hash<Key> >
class lookup_table
{
private:
class bucket_type
{
private:
typedef std::pair<Key, Value> bucket_value;
typedef std::list<bucket_value> 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<boost::shared_mutex> 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<boost::shared_mutex> 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<boost::shared_mutex> lock(mutex);
bucket_iterator const found_entry = find_entry_for(key);
if (found_entry != data.end()) {
data.erase(found_entry);
}
}
};
std::vector<std::unique_ptr<bucket_type> > 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<Key,Value> get_map() const
{
std::vector<boost::unique_lock<boost::shared_mutex> > locks;
for (unsigned i = 0; i < buckets.size(); ++i)
{
locks.push_back(boost::unique_lock<boost::shared_mutex>(
buckets[i].mutex));
}
std::map<Key,Value> 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<int,std::string> t;
t.add_or_update_mapping(1,"hello");
std::cout << "value for 1 is " << t.value_for(1) << std::endl;
return 0;
}

112
ch6/queue.cpp Normal file
View File

@@ -0,0 +1,112 @@
#include <iostream>
#include <cstdio>
#include <queue>
#include <thread>
#include <memory>
#include <mutex>
#include <condition_variable>
template <typename T>
class queue
{
private:
mutable std::mutex mut;
std::queue<std::shared_ptr<T> > data_queue;
std::condition_variable data_cond;
public:
queue(){}
queue(const queue& other)
{
std::lock_guard<std::mutex> lk(other.mut);
data_queue = other.data_queue;
}
void push(T new_value)
{
std::shared_ptr<T> data(new T(new_value));
std::lock_guard<std::mutex> lk(mut);
data_queue.push(data);
data_cond.notify_one();
}
void wait_and_pop(T& value)
{
std::unique_lock<std::mutex> 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<T> wait_and_pop()
{
std::unique_lock<std::mutex> lk(mut);
data_cond.wait(lk, [&]{return !data_queue.empty();});
/*
while (data_queue.empty()) {
data_cond.wait(lk);
}
*/
std::shared_ptr<T> res = data_queue.front();
data_queue.pop();
return res;
}
bool try_pop(T& value)
{
std::lock_guard<std::mutex> lk(mut);
if (data_queue.empty())
return false;
value = *data_queue.front();
data_queue.pop();
}
std::shared_ptr<T> try_pop()
{
std::lock_guard<std::mutex> lk(mut);
if (data_queue.empty())
return std::shared_ptr<T>();
std::shared_ptr<T> res = data_queue.front();
data_queue.pop();
return res;
}
bool empty() const
{
std::lock_guard<std::mutex> lk(mut);
return data_queue.empty();
}
};
void push(queue<int>* 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<int>* q)
{
for (int i = 0; i < 10; ++i) {
printf("poping %d\n", *q->wait_and_pop());
}
}
int main()
{
queue<int> q;
std::thread t1(push,&q);
std::thread t2(pop,&q);
t1.join();
t2.join();
return 0;
}

94
ch6/queuelist.cpp Normal file
View File

@@ -0,0 +1,94 @@
#include <iostream>
#include <queue>
#include <memory>
#include <thread>
#include <mutex>
template <typename T>
class queue
{
private:
struct node
{
std::shared_ptr<T> data;
std::unique_ptr<node> next;
};
std::mutex head_mutex;
std::unique_ptr<node> head;
std::mutex tail_mutex;
node *tail;
node *get_tail()
{
std::lock_guard<std::mutex> tail_lock(tail_mutex);
return tail;
}
std::unique_ptr<node> pop_head()
{
std::lock_guard<std::mutex> head_lock(head_mutex);
if (head.get() == get_tail()) {
return nullptr;
}
std::unique_ptr<node> 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<T> try_pop()
{
std::unique_ptr<node> old_head = pop_head();
return old_head ? old_head->data : std::shared_ptr<T>();
}
void push(T new_value)
{
std::shared_ptr<T> new_data(
std::make_shared<T>(std::move(new_value)));
std::unique_ptr<node> p(new node);
node *const new_tail = p.get();
std::lock_guard<std::mutex> tail_lock(tail_mutex);
tail->data = new_data;
tail->next = std::move(p);
tail = new_tail;
}
};
void push(queue<int>* q)
{
for (int i = 0; i < 10; ++i) {
printf("pushing %d\n", i);
q->push(i);
}
}
void pop(queue<int>* q)
{
int i = 0;
while (true) {
if (std::shared_ptr<int> p = q->try_pop()) {
printf("poping %d\n", *p);
++i;
}
if (i == 10) break;
}
}
int main()
{
queue<int> q;
std::thread th1(push,&q);
std::thread th2(pop,&q);
th1.join();
th2.join();
return 0;
}

154
ch6/queuelist2.cpp Normal file
View File

@@ -0,0 +1,154 @@
#include <iostream>
#include <queue>
#include <memory>
#include <thread>
#include <mutex>
#include <condition_variable>
template <typename T>
class queue
{
private:
struct node
{
std::shared_ptr<T> data;
std::unique_ptr<node> next;
};
std::mutex head_mutex;
std::unique_ptr<node> head;
std::mutex tail_mutex;
node *tail;
std::condition_variable data_cond;
node *get_tail()
{
std::lock_guard<std::mutex> tail_lock(tail_mutex);
return tail;
}
std::unique_ptr<node> pop_head()
{
std::unique_ptr<node> old_head = std::move(head);
head = std::move(old_head->next);
return old_head;
}
std::unique_ptr<node> try_pop_head()
{
std::lock_guard<std::mutex> head_lock(head_mutex);
if (head.get() == get_tail()) {
return std::unique_ptr<node>();
}
return pop_head();
}
std::unique_ptr<node> try_pop_head(T& value)
{
std::lock_guard<std::mutex> head_lock(head_mutex);
if (head.get() == get_tail()) {
return std::unique_ptr<node>();
}
value = std::move(*head->data);
return pop_head();
}
std::unique_lock<std::mutex> wait_for_data()
{
std::unique_lock<std::mutex> head_lock(head_mutex);
data_cond.wait(head_lock, [&]{return head.get() != queue::get_tail();});
return std::move(head_lock);
}
std::unique_ptr<node> wait_pop_head()
{
std::unique_lock<std::mutex> head_lock(wait_for_data());
return pop_head();
}
std::unique_ptr<node> wait_pop_head(T& value)
{
std::unique_lock<std::mutex> 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<T> try_pop()
{
std::unique_ptr<node> old_head = try_pop_head();
return old_head ? old_head->data : std::shared_ptr<T>();
}
bool try_pop(T& value)
{
std::unique_ptr<node> const old_head = try_pop_head(value);
return old_head;
}
std::shared_ptr<T> wait_and_pop()
{
std::unique_ptr<node> const old_head = wait_pop_head();
return old_head->data;
}
void wait_and_pop(T& value)
{
std::unique_ptr<node> const old_head = wait_pop_value(value);
}
void push(T new_value)
{
std::shared_ptr<T> new_data(
std::make_shared<T>(std::move(new_value)));
std::unique_ptr<node> p(new node);
{
std::lock_guard<std::mutex> 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<std::mutex> head_lock(head_mutex);
return (head.get(0 == get_tail()));
}
};
void push(queue<int>* q)
{
for (int i = 0; i < 10; ++i) {
printf("pushing %d\n", i);
q->push(i);
}
}
void pop(queue<int>* q)
{
int i = 0;
for (int i = 0; i < 10; ++i) {
printf("poping %d\n", *q->wait_and_pop());
}
}
int main()
{
queue<int> q;
std::thread th1(push,&q);
std::thread th2(pop,&q);
th1.join();
th2.join();
return 0;
}

62
ch6/stack.cpp Normal file
View File

@@ -0,0 +1,62 @@
#include <exception>
#include <iostream>
#include <stack>
#include <memory>
#include <thread>
#include <mutex>
template <typename T>
class stack
{
private:
std::stack<T> data;
mutable std::mutex m;
public:
stack(){}
stack(const stack& other)
{
std::lock_guard<std::mutex> lock(other.m);
data = other.data;
}
stack& operator=(const stack&) = delete;
void push(T new_value)
{
std::lock_guard<std::mutex> lock(m);
data.push(new_value);
}
std::shared_ptr<T> pop()
{
std::lock_guard<std::mutex> lock(m);
if (data.empty()) throw std::underflow_error("empty stack");
std::shared_ptr<T> const res(new T(data.top()));
data.pop();
return res;
}
void pop(T& value)
{
std::lock_guard<std::mutex> lock(m);
if (data.empty()) throw std::underflow_error("empty stack");
value = data.top();
data.pop();
}
bool empty() const
{
std::lock_guard<std::mutex> lock(m);
return data.empty();
}
};
int main()
{
stack<int> s;
s.push(1);
std::cout << *s.pop() << std::endl;
}