chapter 6 code
This commit is contained in:
34
ch6/Makefile
Normal file
34
ch6/Makefile
Normal 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
126
ch6/list.cpp
Normal 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
133
ch6/lookuptable.cpp
Normal 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
112
ch6/queue.cpp
Normal 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
94
ch6/queuelist.cpp
Normal 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
154
ch6/queuelist2.cpp
Normal 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
62
ch6/stack.cpp
Normal 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;
|
||||||
|
}
|
||||||
|
|
||||||
Reference in New Issue
Block a user