C++并发编程之一 初识线程和线程管控

C++线程同步——阻塞线程的方法 C头文件 <semaphore.h>中 sem_wait() 会阻塞当前线程 sem_trywait() 返回错误而不是阻塞调用 sem_timedwait() sem_timedwait的abs_timeout参数指定了调用应该阻塞的时间限制 信号量 信号量 (semaphore) 是一种轻量的同步原件,用于制约对共享资源的并发访问。在可以使用两者时,信号量能比条件变量更有效率。 定义于头文件 <semaphore> counting_semaphore 实现非负资源计数的信号 阅读详情

“你最熟悉的hello world”

在一个进程或者线程里面输出 "hello world"是怎么做的呢?

#include <iostream>
int main()
{
    std::cout << "Hello World!\n";
}

在该线程中起始函数为main函数,当输出完"hello world",该线程便终止了。

如果我们想另外开辟一个线程输出"hello world"该如何操作呢?在C++11中便已经封装好了管控线程的函数。
我们可以引入头文件,来启动线程。

#include <iostream>
#include <thread>
void hello() {
    std::cout << "hello world" << std::endl;
}
int main()
{
    std::cout << "I want start a new thread to print hello world." << std::endl;
    //创建子线程并传递入口函数
    std::thread t(hello);
    //调用join函数,阻塞当前主线程,直到子线程运行结束
    t.join();
    return 0;
}

在本例子中 t 作为 std::thread对象将函数hello()作为新线程的入口函数。std::thread对象的地址C++运行时系统动态分配的,通常在创建线程时自动分配。该地址指向新线程的控制结构,它包含线程的一些信息,比如线程id,状态,堆栈指针等等。我们看到 hello 作为一个参数传入到线程构造函数中,该参数通常是一个可调用对象(函数指针,lambda表达式或函数对象),'std::thread’对象将可调用对象的地址保存到新线程的控制结构里面,以便在运行的时候调用。

而’std::thread::join()'是一个成员函数,它用于等待该线程对象相关联的线程运行结束,调用 ‘join()’ 函数会阻塞当前线程的运行,直到该线程对象相关联的线程执行完成为止。
使用 ‘std::thread::join’ 的目的就是为了让主线程等待所有的子线程运行结束后再退出。
注意:一个线程对象只能调用一次 'std::thread::join()'函数,否则会触发 'std::system_error’异常。

线程管控(等待、分离、传递参数、移交线程归属权)

线程分离

上面讲到了 ‘std::thread::join()’ 函数阻塞主线程等待子线程执行结束,那如果用户不想等待呢?当然也有办法,那就是使用 ‘std::thread::detach()’ 函数使线程对象与其管理的执行线程相分离,将一个线程对象与其执行线程分离后,这个线程对象就不再与其所管理的执行线程相关联,它的执行状态将与执行线程独立。

这意味着线程的执行将会在后台继续进行,即使线程对象被销毁了,执行线程仍然可以继续执行。但我们在使用这个函数的时候,需要检验一下线程对象是否可连接(即线程对象和相关联的执行线程是否绑定),如果可连接,那么可以执行分离。但是如果不可连接,依然调用’std::thread::detach()',将导致程序终止。

线程对象在分离之后将无法重新连接到执行线程,因此需要确保不需要再次连接到执行线程。被分离出去的线程又可被称为守护线程(daemon thread)。

#include <iostream>
#include <thread>

void hello() {
    std::cout << "hello world" << std::endl;
}
int main()
{
    std::cout << "I want start a new thread to print hello world." << std::endl;
    std::thread t(hello);
    if (t.joinable()) {
        t.detach();
        std::cout << "Thread is joinable\n";
    }
    else {
        std::cout << "Thread is not joinable\n";
    }
    std::cout << "Exiting main function\n";
    return 0;
}

注意: 当线程分离时,对于可调用对象中含有指针或引用,一定要谨慎操作,如果指针或引用指向了一个主线程的一个已摧毁变量,程序就会出问题。解决方法:可令线程完全自含,将数据复制到新线程的内部,而不是共享数据。

向线程函数传递参数

我们已经学会了创建线程、等待子线程、分离子线程,那么当我们新创建的线程需要参数运行时,我们该如何想向线程函数中传递参数呢?有如下几种方法可以传递。

  • 使用std::thread的构造函数
    std::thread类提供了多个构造函数,其中一个构造函数可以接受一个可调用对象和多个参数,可以使用这个构造函数来向线程中传递参数。
#include <iostream>
#include <thread>

void func(int arg1, int arg2)
{
    std::cout << "arg1 = " << arg1 << ", arg2 = " << arg2 << std::endl;
}

int main()
{
    int arg1 = 10;
    int arg2 = 20;

    std::thread t(func, arg1, arg2);

    t.join();
    return 0;
}

在这个示例中,调用 std::thread 的构造函数时,除了要指定线程函数 func 外,还将 arg1 和 arg2 作为构造函数的参数传递给了该线程。这样,在创建新线程时,这两个参数的值会被复制到新线程的私有存储空间中。因此,在新线程中修改这两个参数的值不会影响主线程中这两个参数的值,也不会影响其他线程对这两个参数的访问。

由于这里使用的是值传递,所以可以避免线程之间的竞争和共享数据的问题。但也需要注意,如果参数的拷贝开销很大,可能会影响程序的效率。如果需要在多个线程之间共享数据,则需要使用其他的线程通信机制来保证数据的同步和一致性。

  • 那么如果我想要引用传递,在新线程中更改参数也会影响到主线程中的参数呢?可以使用这样的方式:可以使用到 std::ref() 函数
#include <iostream>
#include <thread>

void func(int& a, int& b) {
	a++;
	b++;
	std::cout << "a is " << a << " , b is " << b << std::endl;
}

int main() {
	int argc1 = 10;
	int argc2 = 20;
	std::thread t(func, std::ref(argc1), std::ref(argc2));
	t.join();
	std::cout << "main thread argc1 is " << argc1 << " , argc2 is " << argc2 << std::endl;
	return 0;
}
  • 使用Lambda表达式
    Lambda表达式是C++11引入的一个新特性,可以用于创建匿名函数对象。使用Lambda表达式可以方便地向线程中传递参数。
#include <iostream>
#include <thread>

int main()
{
    int arg1 = 10;
    int arg2 = 20;

    std::thread t([&arg1, &arg2]() {
        std::cout << "arg1 = " << arg1 << ", arg2 = " << arg2 << std::endl;
    });

    t.join();
    return 0;
}

在上述示例代码中,使用Lambda表达式向线程t中传递参数arg1和arg2。
需要注意的是,如果要向线程中传递引用类型的参数,需要使用std::ref()函数将参数包装为一个引用包装器。例如,可以使用std::thread t(func, std::ref(arg1), std::ref(arg2))向线程中传递引用类型的参数。

  • 传递成员函数
    要在 std::thread 中使用成员函数,需要将成员函数作为线程函数,并将类对象的指针作为参数传递给 std::thread 的构造函数。
#include <iostream>
#include <thread>
#include <functional>

class MyClass
{
public:
    void func(int arg)
    {
        std::cout << "arg = " << arg << std::endl;
    }
};

int main()
{
    MyClass myObj;
    int arg = 10;

    std::thread t(&MyClass::func, &myObj, arg);

    t.join();

    return 0;
}

在这个示例中,通过&MyClass::func获取函数的地址,并将对象指针&myObj 和参数arg传递给了std::thread的构造函数中,由于成员函数func()需要类对象的成员变量和其他成员函数,所以需要将类对象的指针作为第一个参数传递给线程函数。

  • 参数移动而不能复制的传递参数
    使用 std::move 来传递只能移动但不能复制的对象。这种方式适用于需要将对象的所有权转移给新线程的情况,可以避免在多线程环境下进行复制或共享对象的操作。
#include <iostream>
#include <thread>
#include <string>

void func(std::string&& str)
{
    std::cout << "str = " << str << std::endl;
}

int main()
{
    std::string str = "hello";

    std::thread t(func, std::move(str));

    t.join();

    return 0;
}

在这个示例中,将字符串 str 作为右值引用传递给线程函数 func。由于右值引用表示的是对象的所有权,因此在传递参数时需要使用 std::move 来将对象的所有权转移给新线程。
需要注意的是,一旦对象的所有权被转移,原始的对象将不再可用,因此在使用 std::move 传递参数时需要小心。此外,如果多个线程同时访问同一个对象,可能会导致竞争条件的发生,需要采取适当的同步措施来避免这个问题。

移交线程归属权

  • 首先可以使用std::thread::swap()函数进行交换线程所有权
#include <iostream>
#include <thread>

void my_thread(int n) {
    std::cout << "Thread " << n << " is running." << std::endl;
}

int main() {
    std::thread t1(my_thread, 1);
    std::thread t2;

    // 交换两个线程的内部状态,使得t2获得了t1的执行函数和其他内部状态
    t1.swap(t2);

    // 等待t2执行完成
    t2.join();

    std::cout << "Thread 1 has been moved to t2." << std::endl;

    return 0;
}
  • 还有一种方法可以移交线程所有权,就是使用std::move()
#include <iostream>
#include <thread>

void func()
{
    std::cout << "Thread running" << std::endl;
}

int main()
{
    std::thread t(func);

    // 移交线程所有权给t2
    std::thread t2(std::move(t));

    t2.join();
    return 0;
}

在运行时选择线程数量

我们已经学会了创建线程、传递线程参数、转移线程所有权,那么我们在写程序的时候该开多少线程合适呢?我们可以通过std::thread::hardware_concurrency()函数,返回一个 unsigned int 值,表示当前系统支持的并发线程数。这个值并不是一个精确的硬件限制,而是一个估计值,取决于当前系统的硬件和其他运行时因素。通常情况下,这个值与 CPU 的核心数有关,但是在某些情况下,它可能会受到其他因素的影响,例如 CPU 频率、内存带宽、I/O 带宽等。

在编写多线程程序时,使用 std::thread::hardware_concurrency() 函数可以帮助我们根据系统能力来确定线程数量,从而最大化系统资源的利用率。例如,以下代码片段使用 std::thread::hardware_concurrency() 函数来确定系统支持的最大线程数量:

#include <iostream>
#include <thread>

int main()
{
    unsigned int n = std::thread::hardware_concurrency();
    std::cout << "This system can run " << n << " concurrent threads." << std::endl;
    return 0;
}

识别线程

我们可以使用 std::this_thread::get_id() 函数来获取当前线程的 ID,这个 ID 是一个唯一的整数,表示当前线程的身份。例如,以下代码片段演示了如何获取当前线程的 ID 并输出它的值:

#include <iostream>
#include <thread>

void func()
{
    std::cout << "Thread ID = " << std::this_thread::get_id() << std::endl;
}

int main()
{
    std::thread t(func);
    std::cout << "Main thread ID = " << std::this_thread::get_id() << std::endl;
    t.join();
    return 0;
}

需要注意的是,如果在单线程程序中调用 std::this_thread::get_id(),它将返回一个默认的 ID,但是这个 ID 并不代表任何真实的线程。所以,这个函数只能用于多线程程序中。

std::thread::id 是一个类型,表示线程的唯一标识符。每个线程都有一个不同的 std::thread::id,可以通过 std::thread::get_id() 函数获取。

#include <iostream>
#include <thread>

void func()
{
    std::cout << "Thread ID = " << std::this_thread::get_id() << std::endl;
}

int main()
{
    std::thread t1(func);
    std::thread t2(func);
    
    if (t1.get_id() == t2.get_id()) {
        std::cout << "Thread IDs are the same." << std::endl;
    } else {
        std::cout << "Thread IDs are different." << std::endl;
    }
    
    std::cout << "t1 ID = " << t1.get_id() << std::endl;
    std::cout << "t2 ID = " << t2.get_id() << std::endl;
    
    t1.join();
    t2.join();
    
    return 0;
}

上述代码创建了两个新线程 t1 和 t2,然后通过 std::thread::get_id() 函数获取它们的 std::thread::id。接着,代码比较了这两个 ID 是否相同,以及打印了每个线程的 ID。最后,通过调用 std::thread::join() 函数等待线程结束。
如果知道线程对象名称就可以使用std::thread::get_id()来获取 std::thread::id, 如果想在该线程中不用知道线程绑定对象名称就获取 std::thread::id ,可以使用std::this_thread::get_id() 来获取。

MMWCAS-DSP-EVM与AWR2243实战:从开箱到数据采集的完整避坑指南 本文提供了MMWCAS-DSP-EVM与AWR2243毫米波雷达评估板从开箱、软硬件准备、固件烧录到数据采集的完整实战指南。重点解析了硬件连接、软件版本匹配、固件烧录、网络配置及MMWave Studio GUI操作等关键步骤,并汇总了常见问题排查方法,帮助开发者快速上手并规避常见陷阱。 阅读详情

相关推荐

datax web升级springboot3 jdk17

datax web但GitHub上还是springboot2,没有升级过,最近扫漏洞发现spring-core漏洞必须升级到6.x才能解决,这时不得不将springboot升级到3.x,随之而来是jdk、mybatis-plus等等的升级,调整了几天才没问题,痛苦的开发人生~~以上,有疑问欢迎留言。

liyinglong1023的博客 973

c++ 线程使用详解 创建线程的多种方法

函数原型: f:任何可调用对象。 args:传递给 f 的参数 构造新对象并将它与执行线程关联。

luohaha66的博客 1936

SAP 物料的分割评估

SAP 物料的分割评估 前言 本文主要讲解SAP中物料的分割评估,通过分割评估来区分出同一物料不同来源下的核算方式。例如:同一物料分为自产或者采购,或者同一物料分为进口或者国内采购等。 一、概述 分割评估一般用于以下场景: 1、物料分为内部采购和外部采购; 2、物料分属于进口或者国内采购; 3、物料分属于不同的批次; 4、物料分为自制或者采购。 由于物料的来源不同可能导致物料的价格或者性质不同,需要用不同价格来区分出 二、配置步骤 1.激活分割评估 ...

五谷散熊 6791

C++ 线程同步 异步 阻塞 非阻塞概念介绍 及 C++ 实践

文章目录基础概念介绍c++ 11 中多线程以及异步处理 基础概念介绍 基础概念介绍参考博文:https://www.cnblogs.com/mhq-martin/p/9035640.html 我们经常看到线程同步 进程同步 有时候可能还会听到线程异步之类的说法,这些概念容易让人混淆,所以首先我们把这些概念拆开来一个一个看,然后他们组合起来应该就容易理解了 同步 就是按照顺序一件一件的做。专业一点就是如果调用了一个函数,就需要等这个函数运行结束,才能执行后面的代码。 异步 就是很多事情一起做,顺序不能确定。专

weixin_42376458的博客 6492

hMailServer安装配置

hMailServer安装配置 使用宝塔面板上的宝塔邮件服务器2.1版本,进行安装hMailServer。 宝塔在安装hMailServer是有做了一些配置,如果是手工安装需要注意一下配置点: 1、\hMailServer\Bin 目录下增加mysql连接文件libmysql.dll,要去下载32位的。 libmysql.dll下载 链接:https://pan.baidu.com/s/1YGJXzjowlJ9n_MiqB4xiqw 提取码:wz90 2、 需要提前安装mysql,并创建hM.

王者的博客 5863

SAP DRC 是什么?一文读懂 SAP Document and Reporting Compliance 的定位、架构与落地案例

把视线拉长,会发现SAP DRC的价值并不仅是用来交差的工具。它更像是企业在全球化经营中建设的一套公共底座:既能以最低的重复成本去应对各国不断演进的监管要求,也能为财务数字化与供应链协同提供可信数据回路。依托本地与云的分层职责、与的生态联动、以及按国家不断更新的任务目录,企业可以将合规变成一种标准化、工程化、可持续运营的能力。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 1646

c++ 线程阻塞等待别人激活

c++ 线程阻塞等待别人激活

xie__jin__cheng的博客 2285

药物对接仿真软件:HADDOCK_(5).HADDOCK中蛋白质-配体对接流程

半柔性能量最小化阶段是在刚体能量最小化的基础上,允许配体的部分柔性,通过优化配体的构象来进一步提高对接的准确性。半柔性能量最小化阶段是在刚体能量最小化的基础上,允许配体的部分柔性,通过优化配体的构象来进一步提高对接的准确性。如果是PDB格式,确保文件包含所有必要的原子信息。对接完成后,HADDOCK会生成一系列的输出文件,包括对接后的蛋白质-配体复合物结构文件、能量评分文件和统计分析文件。对接完成后,HADDOCK会生成一系列的输出文件,包括对接后的蛋白质-配体复合物结构文件、能量评分文件和统计分析文件。

kkchenjj的博客 1077

C++ 多线程学习04 多线程状态与互斥锁

初始化→就绪态:操作系统为线程分配好了资源,将其挂载CPU的就绪队列上。 就绪→运行:该线程排在就绪队列队首元素,且CPU调度到了该线程(如时间片轮转算法、高响应比优先算法、短作业优先等),将其交给CPU去运行 运行→就绪:正在CPU上运行的线程用于CPU的调度中断了运行,挂载就绪队列队尾 就绪→阻塞:X 运行→阻塞:当进程请求某一资源(如外设)的使用和分配或等待某一事件的发生(如IO操作的完成)时,它就从运行状态转换为阻塞状态。进程以系统调用的形式请求操作系统提供服务,这是一种特殊的、由运行用户态程序调用

qq_42567607的博客 1604

基于STM32、HAL库的WF282A气压传感器 驱动程序设计

测量范围:0-2.5MPa(可根据需求选择其他量程)输出方式:I2C或SPI数字接口。温度补偿范围:-20℃~85℃。低功耗设计,适合电池供电应用。工作电压:3.3V/5V。精度:±0.1%FS。

corlin6688的博客 394

SerDes学习笔记:DFE均衡架构示例(USB3.1、PCIe3.0\4.0)

本文探讨了DFE均衡器架构在不同数据接口中的应用特性。研究表明,抽头数量随数据速率提升而增加,1-16抽头架构较为常见。通过PCIeGen3/4实例分析,对比了单抽头、双抽头和15抽头DFE的性能差异,证明多抽头结构能通过精细调节有效提升噪声容限和降低误码率。文章详细阐述了DFE工作原理,包括其通过反馈信号对输入信号的补偿机制,以及不同抽头对消除码间干扰的作用。实验采用8Gbps速率(125ps/UI)进行波形仿真,直观展示了均衡处理前后的信号变化,为理解信道均衡技术提供了重要参考。

一只豌豆象的博客 517

C++并发编程之一 初识线程和线程管控_获取有名管道中的结果 单独起一个线程c++

当然也有办法,那就是使用 ‘std::thread::detach()’ 函数使线程对象与其管理的执行线程相分离,将一个线程对象与其执行线程分离后,这个线程对象就不再与其所管理的执行线程相关联,它的执行状态将与执行线程独立。,它包含线程的一些信息,比如线程id,状态,堆栈指针等等。而’std::thread::join()'是一个成员函数,它用于等待该线程对象相关联的线程运行结束,调用 ‘join()’ 函数会阻塞当前线程的运行,直到该线程对象相关联的线程执行完成为止。被分离出去的线程又可被称为。

2401_89191848的博客 1015

第一部分:VTK基础入门(第1章:VTK简介与概述)

VTK简介与核心特性概述 VTK(Visualization Toolkit)是一个开源的跨平台C++类库,专用于3D计算机图形学、图像处理和科学可视化。由Kitware公司开发,VTK自1993年起源以来,经历了开源化、成熟化和现代化多个发展阶段,现已成为科学可视化的核心工具之一。 VTK的核心特性包括: 管道架构:模块化设计实现数据流管理 丰富的数据支持:处理多边形数据、图像数据等 强大的渲染能力:集成OpenGL,支持多种渲染技术 最新版本VTK 9.4.2增强了现代C++支持,优化了内存管理,并提升

仰望星空的博客 2356

并发编程(2)——线程管控

如果存在一个容器 std::vector<std::thread>,当使用 push_back 将一个线程对象添加到这个容器时,实际上会调用 std::thread 的拷贝构造函数,但是std::thread 将拷贝构造函数delete,编译器会报错。std::vector 中,原始的 std::thread 对象将失去对该线程的所有权(即该对象变为无效),并且只能在 std::vector 中的元素上调用 join() 或 detach() 来管理这个线程的生命周期。当取消被执行时,进行清理和终止线程。

m0_63086198的博客 1221

深度学习工具包 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")

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

[C++ 并发编程] 线程管控

线程管控

A_ns_wer_的博客 1200

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

C++并发编程实战 #1 线程管控

如果给定一个线程,只要令thread对象与之关联,就能管控该线程的几乎每个细节。每个C++程序都至少有一个线程,即运行main()的线程,它由C++运行时系统启动。随后,可以发起更多线程,以别的函数作为入口。main()函数返回时,程序就会推出;同样,当入口函数返回时,对应线程随之结束。

A11en3的博客 1106

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

C++多线程之线程管控

摘要:本文详细介绍了C++11标准库中的线程操作,主要内容包括:1. 线程创建方式(普通函数、函数对象、lambda表达式)及避免被解释为函数声明的方法;2. 线程分离(detach)和等待(join)的实现,包括异常情况处理和RAII技术应用;3. 线程参数传递机制(普通参数、指针、引用、成员函数、unique_ptr等);4. 线程归属权转移的实现方法;5. C++20新增的jthread特性及其自动join和中断机制;6. 运行时线程数量选择策略;7. 线程ID的获取和应用场景。文章通过代码示例展示了

andre617的专栏 842

15.C++11线程—线程管控(笔记)

然而分离的线程确实仍在后台运行,其归属权和控制权都转移给C++运行时库(runtime library,又名运行库),由此保证,一旦线程退出,与之关联的资源都会被正确回收。假如代码必须确保新线程先行结束,之后当前线程的函数才退出,那么关键在于,全部可能得退出路径都必须保证这种先后次序,无论是正常退出,还是抛出异常。全序关系,简称全序,又名线性序、简单序或非严格排序,是在集合上的反对称的、传递的和完全的任何二元关系。作为参数,它被复制到属于新线程的存储空间中,并在那里被调用,由新线程执行。

C++方向学习笔记 1116

C++并发编程(1):基本概念、线程管控

主要学习介绍C++并行编程的基础知识,做一些学习记录并分享

工大机器人工作室 1159

C++并发编程 -1.线程管理

本栏主要介绍《C++并发实战编程》这本书,。将按照书目录分为 九章节介绍C++并发编程,尽可能简化本书内晦涩难懂知识点。本章节主要讲解线程使用基础。详细介绍线程使用基础(线程发起、等待、参数、异常处理)、线程管控(归属权、并发数量等)。

qq_45604814的博客 1170

C++并发编程学习笔记

C++并发编程学习笔记

qq_46260032的博客 1167

C++并发编程-2.C++ 线程管控

参考:https://llfc.club/category?catid=225RaiVNI8pFDD5L4m807g7ZwmF#!aid/2Tuk4RfvfBC788LlqnQrWiPiEGW 使用起来比较简单,我们直接构造一个joining_thread对象即可。 5. 选择运行数量 借用C++标准库的std::thread::hardware_concurrency()函数,它的返回值是一个指标,表示程序在各次运行中可真正并发的线程数量.我们可以模拟实现一个并行计算的功能,计算容器内所有

yang_pi_pi的博客 490

c++并发编程

众所周不知,掌握多线程开发得计算机天下。接下来,让我们从C++11标准开始学习并发编程。从线程的管控到线程间共享数据,再到并发操作同步,再到……

Lucky_Cpper的博客 1308

C++并发编程实战读书笔记——线程管理

并发的两种途径:多个进程,每个进程只有一个线程(multiple single-threaded processes);每个进程有多个线程(multiple threads in a single process)。多个单线程/进程的启动和通信开销要比单一进程多线程间的启动和通信大。若不考虑共享内存可能带来的问题,多线程是主流语言(包括C++)更青睐的并发途径。此外,C++标准并未对进程间通信提供...

肥叔菌的博客 8815

C++并发编程(二)线程管控

C++并发编程笔记

CSSS_2021的博客 1787

C++并发:线程管控

每个C++程序都含有至少一个线程,即运行main()的线程,它由C++运行时系统启动。随后程序可以发起更多线程,它们以别的函数作为入口。这些新线程连同起始线程并发运行。当main()返回时,程序就会退出;同样,当入口函数返回时,对应的线程随之终结。如果借std::thread对象管控线程,即可选择等他结束。

FranYeCisco的博客 558
上一篇: std::bind()函数详解
下一篇: 在STL中emplace_back和push_back的区别
ZHAOCHENHAO-
博客等级 码龄10年 2774粉丝 72原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值