线程安全的链表

template<typename T>
class ThreadsafeList
{
    struct Node
    {
        std::mutex m;
        std::shared_ptr<T> data;
        std::unique_ptr<Node> next;

        Node():
            next(nullptr)
        {}

        Node(T const& value):
            data(std::make_shared<T>(value))
        {}
    };

    Node head;

public:
    ThreadsafeList() = default;
    ThreadsafeList(const ThreadsafeList&) = delete;
    ThreadsafeList& operator=(const ThreadsafeList&) = delete;
    ~ThreadsafeList()
    {
        removeIf([](T const&){return true;});
    }

    void pushFront(T const& value)
    {
        auto newNode = std::make_unique<Node>(value);
        std::unique_lock<std::mutex> lock(head.m);
        newNode->next = std::move(head.next);
        head.next = std::move(newNode);
    }

    template<typename Function>
    void forEach(Function f)
    {
        Node* current = &head;
        std::unique_lock<std::mutex> lock(head.m);
        while(auto const next = current->next.get ()){
            std::unique_lock<std::mutex> nextLock(next->m);
            lock.unlock ();
            f(*next->data);
            current = next;
            lock = std::move(nextLock);
        }
    }

    template<typename Predicate>
    std::shared_ptr<T> findFirstIf(Predicate p)
    {
        Node* current = &head;
        std::unique_lock<std::mutex> lock(head.m);
        while(auto const next = current->next.get ()){
            std::unique_lock<std::mutex> nextLock(next->m);
            lock.unlock ();
            if (p(*next->data)){
                return next->data;
            }
            current = next;
            lock = std::move(nextLock);
        }
        return std::shared_ptr<T>();
    }

    template<typename Predicate>
    void removeIf(Predicate p)
    {
        Node* current = &head;
        std::unique_lock<std::mutex> lock(head.m);
        while(auto const next = current->next.get ()){
            std::unique_lock<std::mutex> nextLock(next->m);
            if (p(*next->data)){
                auto oldNext = std::move(current->next);
                current->next = std::move(next->next);
                nextLock.unlock ();
            }
            else{
                lock.unlock ();
                current = next;
                lock = std::move(nextLock);
            }
        }
    }
};
时间: 2024-10-13 19:46:57

线程安全的链表的相关文章

简单实用可线上应用的线程池组件

0 前言 线程池的组件网上很多,之前我自己也尝试写个一个demo,但这些组件一般都比较简单,没有完整的实现后台线程池组件应用的功能.因此,这里我们实现一个可以用在线上环境的线程池组件,该线程池组件具备线程池应用的特性,如下所示: 1. 伸缩性:即线程池中线程的个数应该是动态变化的.繁忙的时候可以申请更多的线程:空闲的时候则注销一部分线程. 2. 线程状态:线程池中对线程的管理引入睡眠.唤醒机制.当线程没有任务在运行时,使线程处于睡眠状态. 3. 线程管理:对线程池中线程的申请和注销,不是通过创建

linux下的线程池

什么时候需要创建线程池呢?简单的说,如果一个应用需要频繁的创建和销毁线程,而任务执行的时间又非常短,这样线程创建和销毁的带来的开销就不容忽视,这时也是线程池该出场的机会了.如果线程创建和销毁时间相比任务执行时间可以忽略不计,则没有必要使用线程池了. 下面是Linux系统下用C语言创建的一个线程池.线程池会维护一个任务链表(每个CThread_worker结构就是一个任务).   pool_init()函数预先创建好max_thread_num个线程,每个线程执thread_routine ()函

单向链表上是否有环

详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcyt115 有一个单链表,其中可能有一个环,也就是某个节点的next指向的是链表中在它之前的节点,这样在链表的尾部形成一环. 问题: 1.如何判断一个链表是不是这类链表?2.如果链表为存在环,如果找到环的入口点? 解答: 1.最简单的方法, 用一个指针遍历链表, 每遇到一个节点就把他的内存地址(java中可以用object.hashcode())做为key放在一个hashtabl

TCMalloc:线程缓冲的Malloc

这段时间比较闲,研究下内存管理,从官方文档开始啃起<TCMalloc : Thread-Caching Malloc>. 一.动机 TCMalloc要比glibc 2.3的malloc(可以从一个叫作ptmalloc2的独立库获得)和其他我测试过的malloc都快.ptmalloc在一台2.8GHz的P4机器上执行一次小对象malloc及free大约需要300纳秒,而TCMalloc的版本同样的操作大约只需要50纳秒.malloc版本的速度是至关重要的,因为如果malloc不够快,应用程序的作

java线程(四) : 对象的组合

设计线程安全的类: 在设计线程安全类的过程中,需要包含以下三个基本要素: 找出构成对象状态的所有变量 找出约束状态变量的不变性条件 建立对象状态的并发访问策略 如果不了解对象的不变性条件与后验条件,那么就不能确保线程安全性.要满足在状态变量的有效值或状态转换上的各种约束条件,就需要借助于原子性与封装性. 如果在操作中包含有基于状态的先验条件,那么这个操作就称为依赖状态的操作,在并发程序中一直要等到先验条件为真,然后再执行该操作.在java中,等待某个条件为真的各种内置机制(包括等待和通知机制)都

基于 JVMTI 实现 Java 线程的监控(转)

随着多核 CPU 的日益普及,越来越多的 Java 应用程序使用多线程并行计算来充分发挥整个系统的性能.多线程的使用也给应用程序开发人员带来了巨大的挑战,不正确地使用多线程可能造成线程死锁或资源竞争,导致系统瘫痪.因此,需要一种运行时线程监控工具来帮助开发人员诊断和跟踪 Java 线程状态的切换.JDK 1.5 及其后续版本提供了监控虚拟机运行状态的接口 JVMTI.本文深入分析了 JVM 中的 Java 线程模型,设计了用于监控线程状态切换的模型,并基于 JVMTI 实现了对 Java 线程切

Linux平台下线程池的原理及实现

转自:http://blog.csdn.net/lmh12506/article/details/7753952 前段时间在github上开了个库,准备实现自己的线程池的,因为换工作的事,一直也没有实现,参考这篇文章准备着手实现一下. 什么时候需要创建线程池呢?简单的说,如果一个应用需要频繁的创建和销毁线程,而任务执行的时间又非常短,这样线程创建和销毁的带来的开销就不容忽视,这时也是线程池该出场的机会了.如果线程创建和销毁时间相比任务执行时间可以忽略不计,则没有必要使用线程池了. 下面是Linu

Java 并发编程(三)为现有的线程安全类中添加新的原子操作

Java 类库中包含许多有用的"基础模块"类.通常,我们应该优先选择重用这些现有的类而不是创建新的类.:重用能降低开发工作量.开发风险(因为现有类都已经通过测试)以及维护成本.有时候,某个线程安全类能支持我们需要的所有操作,但更多的时候,现有的类只能支持大部分的操作,此时就需要在不破坏线程安全的情况下添加一个新的操作. 假设我们需要一个线程安全的链表,他需要提供一个原子的"若没有则添加(Put-If-Absent)"的操作.同步的 List 类已经实现了大部分的功能

Posix线程编程指南(2)

Posix线程编程指南(2) 杨沙洲 原文地址:http://www.ibm.com/developerworks/cn/linux/thread/posix_threadapi/part2/ 线程私有数据 这是一个关于Posix线程编程的专栏.作者在阐明概念的基础上,将向您详细讲述Posix线程库API.本文是第二篇将向您讲述线程的私有数据. 概念及作用 在单线程程序中,我们经常要用到"全局变量"以实现多个函数间共享数据.在多线程环境下,由于数据空间是共享的,因此全局变量也为所有线程