Files
concurrency-in-action/source/listing_6.13.cpp
2018-10-18 00:40:34 -05:00

88 lines
2.1 KiB
C++

#include <memory>
#include <mutex>
template <typename T>
class threadsafe_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:
threadsafe_list() {}
~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<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_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);
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);
}
}
}
};