C++并发编程:线程安全链表

Java 数据结构 线程安全与线程不安全的有哪些? Java开发过程中,Set,Map,List等接口都有很多根据特定场景需要而具体实现的类,面试过程中难免会被考察。 阅读详情

问题描述

最近遇到这么一个问题,一个处理路径的函数,在多线程中被调用,我需要记录某个状态的路径,并在后续当再次处于某个状态时,从链表中将其取出。
为了满足这个需求,用来存储的数据结构要满足:

  1. 线程安全:防止在多线程中错误地对一个变量进行修改
  2. 便于查询
  3. 便于插入、删除
    最终想来选择了线程安全的链表,同时备选的队列,但队列不满足便于查询。

工程实践

作为一个“资深”程序员,我已经熟练掌握了从浩如烟海的百度中用CV大法来进行开发的武功。
所以,我很快地搜索到一段代码:

#include <iostream>

#include <memory>
#include <mutex>

template<typename T>   // 模板
class ThreadsafeList
{
    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:
    ThreadsafeList()
    {}

    ~ThreadsafeList()
    {
        remove_if([](T const&) {return true; });
    }

    ThreadsafeList(ThreadsafeList const& other) = delete;
    ThreadsafeList& operator=(ThreadsafeList 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);
            }
        }
    }
};


int main()
{
    //简单函数功能测试
    ThreadsafeList<int> list;
    list.push_front(1);
    list.for_each([](const int& item) {
        std::cout << item << " ";
        });
    std::cout << std::endl;
    std::shared_ptr<int> ptr=list.find_first_if([](const int& item) {return item == 1; });
    if (ptr.get()!=nullptr) {
        std::cout << *ptr << std::endl;
    }
}

代码分析

在类ThreadSafeList中直接声明了一个结构体变量,比较少见,我也顺手查了一下。

这种方法和在面定义结构体,没什么区别,但是这里需要主义的是,在引用node节点的时候,没有public、private等,所以他是私有的。

class中默认的成员访问权限是private的,而struct中则是public的。

结构体中定义了一个互斥体,这就是保障线程安全的关键所在,每次要对节点进行操作的时候,就先上锁。

 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))    // 拷贝构造函数
        {}
    };

以查询函数为例:
std::unique_lockstd::mutex next_lk(next->m); 这是上锁操作,且使用的是unique_lock,这样就有俩种解锁方式,一种是unlock(),第二种就是在析构函数中解锁了,这也防止我们忘记解锁,这也满足了RAII原则。

    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>();
    }

综上所述,这个类是满足我们选择“线程安全链表”的需求的

代码测试

写一个例子来测试一下。
这是我模拟我的需求写的一个简易例子,多线程对类中同一个数据链表进行读写访问,经过检测,没有出现问题!

// ThreadSafe.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
#include <thread>
#include "thread_safe_list.hpp"
class ThreadSafeListTest
{
public:
    ThreadSafeListTest();
    ~ThreadSafeListTest();
    void thread_safe_list_test1();
    void thread_safe_list_test2();
    void thread_safe_list_test3();
private:
    ThreadsafeList<std::string> _name_list;
};

ThreadSafeListTest::ThreadSafeListTest()
{
}

ThreadSafeListTest::~ThreadSafeListTest()
{
}

void ThreadSafeListTest::thread_safe_list_test1()
{
    std::string target_name = "james";
    _name_list.push_front("harden");

    auto name = _name_list.find_first_if([target_name](const std::string& name) {return target_name == name; });
    if (name != nullptr)
    {
        _name_list.remove_if([target_name](const std::string& name) {return target_name == name; });
    }
}
void ThreadSafeListTest::thread_safe_list_test2()
{
    std::string target_name = "james";
    _name_list.push_front("curry");

    auto name = _name_list.find_first_if([target_name](const std::string& name) {return target_name == name; });
    if (name != nullptr)
    {
        _name_list.remove_if([target_name](const std::string& name) {return target_name == name; });
    }
}
void ThreadSafeListTest::thread_safe_list_test3()
{
    std::string target_name = "Fakejamesjames";
    _name_list.push_front("james");

    auto name = _name_list.find_first_if([target_name](const std::string& name) {return target_name == name; });
    if (name != nullptr)
    {
        _name_list.remove_if([target_name](const std::string& name) {return target_name == name; });
    }
}

void test1(ThreadSafeListTest& tslt)
{
    while (true)
    {
        tslt.thread_safe_list_test1();
    }
}
void test2(ThreadSafeListTest& tslt)
{
    while (true)
    {
        tslt.thread_safe_list_test2();
    }
}
void test3(ThreadSafeListTest& tslt)
{
    while (true)
    {
        tslt.thread_safe_list_test3();
    }
}
int main()
{
    ThreadSafeListTest test;
    std::thread t1(test1, std::ref(test));
    std::thread t2(test2, std::ref(test));
    std::thread t3(test3, std::ref(test));

    t1.join(); // join和主线程不分离,一起结束
    t2.join();
    t3.join();

    system("pause");
    return 0;
}


Windows 多线程编程链表的读写 采用 RWLock结构实现多线程链表的插入,删除以及搜索   //线程类,摘抄Windows 多线程编程的第七章内容 #pragma once #include &lt;Windows.h&gt; #include "stdio.h" typedef struct _RWLock { HANDLE hMutex; HANDLE hDataLock; int Rea... 阅读详情

相关推荐

C++并发实战18: 线程安全的查找表和链表

经常遇见根据关键字查找内容的应用如DNS查询,标准库的std::map系列可供选择,但是它们是非线程安全的,一个线程安全的查找表实现如下,其主要是通过hash函数将各个key分散到具体的bucket中去,每个bucket带有一个共享锁boost::shared_mutex,从而实现线程安全的高并发数据结构: #include #include #include #include #inc

liuxuejiang158的专栏 7674

第十七课:C++多线程的无锁线程安全链表

【代码】第十七课:C++多线程的无锁线程安全链表。

qwers1235的博客 353

C++线程安全LRU缓存实现:从哈希表+双向链表到读写锁优化

缓存是提升系统性能的核心技术之一,其核心原理是通过将高频访问数据存储在快速介质中,减少对慢速存储的访问。LRU(最近最少使用)算法因其实现简单且符合局部性原理,成为最常用的缓存淘汰策略。在并发环境下,保证缓存操作的线程安全至关重要,这直接关系到数据一致性和系统稳定性。通过结合哈希表(提供O(1)查找)与双向链表(维护访问顺序)的基础数据结构,并引入读写锁(如std::shared_mutex)进行并发控制,可以有效实现高效的“读多写少”场景优化。这种设计在Web服务器、数据库连接池等需要高并发访问的**C+

weixin_30512089的博客 1991

ConcurrentHashMap为什么是线程安全的?

ConcurrentHashMap线程安全

zhang2383906154的博客 1万+

Python对接海康威视机器视觉工业相机

工业相机只允许单条连接,也就是说MVS如果连接了相机,python代码就无法获取数据,此时必须。相机工具类(读者直接复制)HKCamera_class.py。博主这里出现了一个警告:获取不到相机参数。四、使用Pycharm打开Python代码示例文件夹。三、找到MVS示例代码(代码在MVS的安装位置)二、解压并安装MVS客户端。一、下载MVS客户端。安装一下opencv。

Good Luck 2万+

告别Arduino IDE!用VSCode搭建Arduino UNO R3开发环境(含代码补全配置)

本文详细指导如何用VSCode替代Arduino IDE搭建Arduino UNO R3开发环境,包含代码补全配置和高效开发技巧。通过安装必要插件、配置项目结构和优化工作流,可显著提升开发效率,特别适合复杂项目开发。文章还提供了常见问题解决方案和高级功能调优方法。

weixin_30698297的博客 479

C++线程安全型双向链表的实现

编写一个线程安全的双向链表,所谓线程安全,就是该链表能够实现多个线程同时正确的增删改链表结点,也就是能够实现对链表这个临界资源的保护。完成该链表后,自己编写一个测试程序,生成多个线程同时读写该链表,验证你的链表执行是否正确,并给出测试报告。(5) Find函数:查找链表中是否有指定的元素,若有,返回能够访问该结点的指针;(1) InitList函数:初始化一个空的双向链表,并初始化各个用于保护链表的信号量。(6) Print函数:打印当前链表中的所有元素。(4) Clear函数:删除链表中的所有结点。

code helper 454

别再到处找模板了!我用这套软著申请材料(含用户手册+源代码模板)两个月搞定

本文提供了一套高效的软著申请材料模板,包括用户手册和源代码模板,帮助开发者两个月内快速完成申请。通过实战指南和常见误区解析,详细介绍了材料准备的规范与技巧,确保格式合规性,大幅提升审核通过率。

weixin_29268637的博客 549

C++ 并发编程:设计线程安全的队列、链表、查询表

一、一般想法 一般想法都会是用std::mutex锁住整个数据结构,如下面代码所示。当然了,这种是一种实现发送,但是不是最好的方式,不能实现最大并发。 github示例代码 #include <iostream> #include <mutex> #include <condition_variable> #include <queue> #include <memory> /* use c++ 11 */ template<typen

wangdamingll的博客 1480

基于SHIS凝视型短波红外高光谱相机(900-1700nm)区分不同宝石的差异性和可分性(宝石分选)

SHIS系列凝视型高光谱相机基于液晶可调谐滤波器(LCTF),通过电控LCTF进行连续细分窄波段分光,对每个波段进行高分辨率的二维面阵成像,进行图像处理后,获得完整的高光谱高清图像序列。具有低功耗、小型化、使用方便和易于扩展的优势。其工作波段覆盖400nm至1000nm,能够捕捉宝石在不同波长下的光谱特征,为宝石鉴定提供了新的工具。

wayho的博客 710

MaaS 商业模式全面分析报告:从技术赋能到商业变现的全链条探索

MaaS(模型即服务)商业模式正成为AI产业主流,2024年上半年中国市场规模达2.5亿元,预计2027年占比将提升至47%。该模式通过云服务提供预训练AI模型,大幅降低企业应用AI的技术门槛和成本。核心盈利方式包括按使用量计费、订阅制、定制化服务等,其中混合模式因灵活性成为趋势。MaaS产业链包含模型提供商、云平台、应用开发商和最终用户,重塑了AI产业格局。随着《数据法案》等监管加强,数据增值服务面临更严格合规要求。未来五年,中国MaaS市场增速预计超50%,用户规模将从2025年2.1亿增至2030年5

芯片行业20年 · 参与定义实现千万级量产出货 · AI芯片PM 2893

OpenGL渲染与几何内核那点事-胡说经典,乐中做学-《C++并发编程实战》-(超级物流中心进化史-(2)

本文探讨了OpenGL渲染与几何内核在并发编程中的应用,通过物流中心案例生动解析了线程安全数据结构的设计演进。从基础的加锁栈、分段锁队列到无锁编程技术,逐步深入并发编程的核心挑战。文章分为两个层次:故事篇以物流场景比喻技术概念,深度解析篇则详细阐述了并发数据结构的设计原则、实现技巧及内存管理方案。重点介绍了线程安全队列的分段锁设计、查找表的分片技术,以及无锁编程中的CAS操作、ABA问题和风险指针等高级话题。该内容基于《C++并发编程实战》第七章,为读者构建高性能并发系统提供了实用指导。

https://ywmhhbaiminminai.github.io/categories/ 546

YOLOv8中的可变形卷积改进 | 从DCNv1到DCNv3的多位置替换可变形卷积保姆级实操

可变形卷积(Deformable Convolution)最早由Dai等人在2017年提出,其核心思想是在标准卷积操作的基础上,引入可学习的偏移量(offsets),使卷积核能够自适应调整其采样位置,从而增强模型对目标变形的感知能力。return x本文通过深入探讨可变形卷积在YOLOv8中的应用,详细介绍了DCNv1、DCNv2和DCNv3的原理和实现,并通过实验验证了其在目标检测任务中的有效性。未来,我们将继续探索更多优化策略和技术,提升YOLOv8模型的性能,以应对更复杂的目标检测任务。

一键难忘的博客 4051

C++并发编程之基于锁的线程安全链表数据结构

设计一个基于锁的线程安全链表数据结构类需要考虑到多线程环境下的并发访问和修改问题。为了保证线程安全,通常会在操作链表时使用锁来同步访问。

捕鲸叉的专栏 519

【PostgreSQL】Windows11下的PostgreSQL数据库安装tds_fdw扩展及使用(图文记录详细步骤)

【详解】【PostgreSQL】Windows11下的PostgreSQL数据库安装tds_fdw扩展及使用

tttzzzqqq2018的博客 2455

【LangChain编程:从入门到实践】实现多模态代理

【LangChain编程:从入门到实践】实现多模态代理 关键词:LangChain, 多模态代理, 自然语言处理, 机器学习, 知识图谱, 对话系统, 代码生成, AI代理 1. 背景介绍 随着人工智

欢迎来到我的优快云空间!这里聚焦AI大模型应用实战,分享前沿技术、实战案例与开发经验。 581

2022-09-29 C++并发编程(二十八)

链表也是以节点套节点的方式连接而成的经典数据结构,对于并发数据结构,链表有几个问题需要解决。首先,链表不能双向访问,以前的文章我们探讨过,对于一个可以从两个方向访问的链表,会最终在某一个时刻碰到同一个数据,并且一路自两个方向延续的加锁可能引发死锁。其次,无法使用迭代器,因为对于一个随时可能被其它线程改变的链表,不能保证迭代器的有效。在极度简化接口的情况下,基本处于可用,难点在于细颗粒度的传递节点及开关锁。

老林的博客 322

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

跑通并深刻理解前两个,同时给出生产者-消费者最佳实践,最后简要说明 Hazard Pointers 原理

即可,后续需要时我再给你完整可编译的 Hazard Pointers + LockFreeQueue 实现。:无锁队列中,线程 A 正在读一个节点时,线程 B 可能已经把它删除了(Use-After-Free)。在高频提交时锁竞争较大,后续可优化为 lock-free + 多队列(per-priority)。前两个,同时给出生产者-消费者最佳实践,最后简要说明 Hazard Pointers 原理。:实现复杂,读操作有一定 overhead。

专注于前沿技术的探索与实践,热衷于从代码逻辑、架构设计到行业应用等多维度深挖技术本质。期待在技术之路上与你共同成长~ 157

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

《C++ Concurrency In Action》part3 线程间共享数据

《C++ Concurrency In Action》part3 线程间共享数据从一个双链表中删除一个节点的步骤如下 1. 找到要删除的节点N 2. 更新前一个节点指向N的指针,让这个指针指向N的下一个节点 3. 更新后一个节点指向N的指针,让这个指正指向N的前一个节点 4. 删除节点N 从一个双链表中删除一个节点 图中b和c在相同的方向上指向和原来已经不一

梁的博客 1253

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

std::mutex的用法

#include #include #include std::list some_list; // 1 std::mutex some_mutex; // 2 void add_to_list(int new_value) { std::lock_guard guard(some_mutex); // 3 some_list.push_back(new_val

锤石的情趣小锁链 5480

C++并发编程-17. 线程安全的链表

前文介绍了如何基于锁实现线程安全的栈和队列结构,以及实现线程安全的查找表,但是我们上次的查找表是基于list实现的,对于锁的精度控制的不是很准确,提及了接下来会介绍精细控制的链表,用来替换查找表中的链表。这一节我们就介绍如何通过锁控制链表访问的精度。

yang_pi_pi的博客 1052

并发编程(17)——基于同步方式的线程安全的链表

文章目录十七、day171. 链表的概念2. 支持多线程、高并发的单向链表2.1 支持前插的单向链表2.2 支持前插and后插的单向链表2.3 测试 十七、day17 上一节实现的查找表中,桶类 bucket_type 使用了C++标准库提供的存储结构链表 list 作为数据存储容器,但通过C++标准库提供的链表 list 存储键值对虽然对并发读不影响(共享锁保证多个线程可以线程安全的读共享数据),但是不能并发写,在同一时间有且仅有一个线程可以修改共享数据(因为C++标准库提供的链表的增删改查是通过同一个互

m0_63086198的博客 1078

C++并发编程 -5. 基于锁实现线程安全的队列和栈容器

如何通过互斥锁和条件变量构建线程安全的队列(栈)在已经介绍过构建线程安全的栈,现在重新回顾。

qq_45604814的博客 1678

并发编程(15)——基于同步方式的线程安全的栈和队列

在上面的代码中,push 和 pop 函数施加同步是用的同一个mutex,这会导致 push 和 pop 在多线程环境中串行化,即,一个线程执行 push ,那么其他线程就没办法执行 pop 或 push,虽然我们通过条件变量挂起了这些线程,避免了算力资源的浪费,但是我们没有办法实现 push 和 pop 的同时调用。获取的尾节点并不是最终的尾节点。其实创建一个智能指针共享资源也会造成一定程度的内存开销,只不过很少,因为智能指针在栈上开辟,占8字节,所以每创建一个新的智能指针,便会在栈上开辟8字节的空间。

m0_63086198的博客 1385

C++实现工业级LRU缓存:从哈希链表到线程安全优化

缓存是提升系统性能的核心技术之一,其核心原理是通过存储热点数据减少对慢速存储的访问。LRU(最近最少使用)淘汰算法因其高效性和实用性,成为缓存系统的关键技术。该算法通过哈希表与双向链表的组合,实现了O(1)时间复杂度的数据访问与淘汰,在数据库、Web服务器等场景中价值显著。本文基于C++ STL,从基础数据结构选型切入,详细剖析了哈希链表的设计与实现,并逐步扩展到模板化、健壮性增强及线程安全等工业级特性。文中深入探讨了迭代器安全、对象生命周期管理等实践要点,并自然融入了“带有效期的lru缓存”优化方向与“内

weixin_33226548的博客 267

C++并发编程学习03:一个简易的线程安全栈实现

线程安全栈 学习内容来自于“C++并发编程实战” #pragma once #include <exception> #include <memory> // std::make_shared 和 智能指针 #include <mutex> // lock_guard #include <stack> struct empty_stack : s...

知其然而后知其所以然 687
上一篇: C++调试内存泄漏
下一篇: std::thread创建线程,使用std::ref()传递类对象参数
CodeBowl
博客等级 码龄5年 7664粉丝 67原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值