muduo库Thread类剖析

muduo 架构解析 muduo是一个基于Reactor模式的C++网络库。它采用非阻塞I/O模型,基于事件驱动和回调。它不仅是学习linux服务端多线程网络编程的入门资料,我们也可以通过它来学习C++11。     Reactor是网络编程的一般范式。我们这里从reactor模式为出发点,根据Reactor模式的特点剖析muduo的架构设计。根据wiki的定义: The reactor design patter 阅读详情

muduo库中的Thread类集合了所有线程的操作,其中还运用了线程安全的观察者模式。

运用shared_ptr和weak_ptr做到了生命周期的管理。


线程类的接口:



代码加注释如下:

Thread.h

#ifndef MUDUO_BASE_THREAD_H
#define MUDUO_BASE_THREAD_H

#include <muduo/base/Atomic.h>
#include <muduo/base/Types.h>

#include <boost/function.hpp>
#include <boost/noncopyable.hpp>
#include <boost/shared_ptr.hpp>
#include <pthread.h>

namespace muduo
{

class Thread : boost::noncopyable
{
 public:
  typedef boost::function<void ()> ThreadFunc;

  explicit Thread(const ThreadFunc&, const string& name = string());
#ifdef __GXX_EXPERIMENTAL_CXX0X__
  explicit Thread(ThreadFunc&&, const string& name = string()); //右值引用,在对象返回的时候不会拷贝构造临时对象,而是和临时对象交换,提高了效率
#endif
  ~Thread();

  void start();
  int join(); // return pthread_join()

  bool started() const { return started_; }
  // pthread_t pthreadId() const { return pthreadId_; }
  pid_t tid() const { return *tid_; }   //由于pthread_t的id号可能是一样的,所以需要用gettid()
  const string& name() const { return name_; }

  static int numCreated() { return numCreated_.get(); }   

 private:
  void setDefaultName();

  bool       started_;
  bool       joined_;
  pthread_t  pthreadId_;
  boost::shared_ptr<pid_t> tid_;    //用来管理生命期
  ThreadFunc func_;                        //线程回调函数
  string     name_;

  static AtomicInt32 numCreated_;   //原子操作
};

}
#endif
Thread.cc

#include <muduo/base/Thread.h>
#include <muduo/base/CurrentThread.h>
#include <muduo/base/Exception.h>
#include <muduo/base/Logging.h>

#include <boost/static_assert.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/weak_ptr.hpp>

#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/prctl.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <linux/unistd.h>

namespace muduo
{
namespace CurrentThread
{
  __thread int t_cachedTid = 0;      //用来缓存的id  //__thread修饰的变量是线程局部存储的,线程不共享,线程安全,解释见下2
  __thread char t_tidString[32];     //tid的字符串表示形式   
  __thread int t_tidStringLength = 6;   
  __thread const char* t_threadName = "unknown";   //每个线程的名称
  const bool sameType = boost::is_same<int, pid_t>::value; //boost::is_same用来检测参数是否是相同的类型,相同返回true。
  BOOST_STATIC_ASSERT(sameType);   //断言相同
}

namespace detail
{

pid_t gettid()
{
  return static_cast<pid_t>(::syscall(SYS_gettid));     //系统调用获取  //解释见下1
}

void afterFork()        //fork之后打扫战场,子进程中执行
{
  muduo::CurrentThread::t_cachedTid = 0;    //当前为0   //1.先清零tid
  muduo::CurrentThread::t_threadName = "main";//为main//为什么要赋值为0和main,因为fork可能在主线程中调用,也可能在子线程中调用。fork得到一个新进程,
  CurrentThread::tid();        //2.此处再缓存tid               //新进程只有一个执行序列,只有一个线程
  // no need to call pthread_atfork(NULL, NULL, &afterFork);   //实际上服务器要么多进程,要么多线程。如果都用,甚至可能死锁,见下5
}

class ThreadNameInitializer   //线程名初始化
{
 public:
  ThreadNameInitializer()
  {
    muduo::CurrentThread::t_threadName = "main";   //由下面的init全局对象先触发构造,主线程的名称为main
    CurrentThread::tid();                    //获得tid
    pthread_atfork(NULL, NULL, &afterFork);    //如果我们调用了fork函数,调用成功后子进程会调用afterfork()
  }
};

ThreadNameInitializer init;  //全部变量类,这个对象构造先于main函数,当我们的程序引入这个库时,这个全局函数直接构造,我们程序的main()函数还没有执行。

struct ThreadData    //线程数据类,观察者模式
{
  typedef muduo::Thread::ThreadFunc ThreadFunc;   
  ThreadFunc func_;
  string name_;
  boost::weak_ptr<pid_t> wkTid_;     

  ThreadData(const ThreadFunc& func,
             const string& name,
             const boost::shared_ptr<pid_t>& tid)    //保存有Thread类的shared_ptr
    : func_(func),
      name_(name),
      wkTid_(tid)
  { }

  void runInThread()    //线程运行
  {
    pid_t tid = muduo::CurrentThread::tid();  //得到线程tid

    boost::shared_ptr<pid_t> ptid = wkTid_.lock();  //尝试将weak_ptr提升为shared_ptr,thread_safe
    if (ptid)     //如果成功
    {
      *ptid = tid;    
      ptid.reset();   //成功了之后把通过智能指针修改父类线程id,该临时shared_ptr销毁掉
    }

    muduo::CurrentThread::t_threadName = name_.empty() ? "muduoThread" : name_.c_str();
    ::prctl(PR_SET_NAME, muduo::CurrentThread::t_threadName);
    try
    {
      func_();    //运行线程运行函数
      muduo::CurrentThread::t_threadName = "finished";   //运行玩的threadname
    }
    catch (const Exception& ex)   //Exception异常
    {
      muduo::CurrentThread::t_threadName = "crashed";
      fprintf(stderr, "exception caught in Thread %s\n", name_.c_str());
      fprintf(stderr, "reason: %s\n", ex.what());
      fprintf(stderr, "stack trace: %s\n", ex.stackTrace());   //打印函数调用栈
      abort();
    }   
    catch (const std::exception& ex)      //标准异常
    {
      muduo::CurrentThread::t_threadName = "crashed";
      fprintf(stderr, "exception caught in Thread %s\n", name_.c_str());
      fprintf(stderr, "reason: %s\n", ex.what());
      abort();
    }
    catch (...)   //其他
    {
      muduo::CurrentThread::t_threadName = "crashed";
      fprintf(stderr, "unknown exception caught in Thread %s\n", name_.c_str());
      throw; // rethrow                 //再次抛出
    }
  }
};

void* startThread(void* obj)   //线程启动
{
  ThreadData* data = static_cast<ThreadData*>(obj);  //派生类指针转化成基类指针,obj是派生类的this指针
  data->runInThread();
  delete data;
  return NULL;
}

}
}

using namespace muduo;

void CurrentThread::cacheTid()   //在这里第一次会缓存tid,并不会每次都systemcall,提高了效率
{
  if (t_cachedTid == 0)
  {
    t_cachedTid = detail::gettid();
    t_tidStringLength = snprintf(t_tidString, sizeof t_tidString, "%5d ", t_cachedTid);
  }
}

bool CurrentThread::isMainThread()  //是否是主线程
{
  return tid() == ::getpid();
}

void CurrentThread::sleepUsec(int64_t usec)    //休眠
{
  struct timespec ts = { 0, 0 };
  ts.tv_sec = static_cast<time_t>(usec / Timestamp::kMicroSecondsPerSecond);
  ts.tv_nsec = static_cast<long>(usec % Timestamp::kMicroSecondsPerSecond * 1000);
  ::nanosleep(&ts, NULL);
}

AtomicInt32 Thread::numCreated_;

Thread::Thread(const ThreadFunc& func, const string& n)
  : started_(false),
    joined_(false),
    pthreadId_(0),
    tid_(new pid_t(0)),
    func_(func),
    name_(n)
{
  setDefaultName();
}

#ifdef __GXX_EXPERIMENTAL_CXX0X__     //C++11标准
Thread::Thread(ThreadFunc&& func, const string& n)
  : started_(false),
    joined_(false),
    pthreadId_(0),
    tid_(new pid_t(0)),
    func_(std::move(func)),
    name_(n)
{
  setDefaultName();
}

#endif
//pthread_join()和pthread_detach()都是防止现成资源泄露的途径,join()会阻塞等待。
Thread::~Thread()    //这个析构函数是线程安全的。析构时确认thread没有join,才会执行析构。即线程的析构不会等待线程结束
{                                    //如果thread对象的生命周期长于线程,那么可以通过join等待线程结束。否则thread对象析构时会自动detach线程,防止资源泄露
  if (started_ && !joined_)   //如果没有join,就detach,如果用过了,就不用了。
  {
    pthread_detach(pthreadId_);
  }
}

void Thread::setDefaultName()   //相当于给没有名字的线程起个名字 "Thread %d"
{
  int num = numCreated_.incrementAndGet();  //原子操作
  if (name_.empty())
  {
    char buf[32];
    snprintf(buf, sizeof buf, "Thread%d", num);
    name_ = buf;
  }
}

void Thread::start()   //线程启动
{
  assert(!started_);
  started_ = true;
  // FIXME: move(func_)
  detail::ThreadData* data = new detail::ThreadData(func_, name_, tid_);
  if (pthread_create(&pthreadId_, NULL, &detail::startThread, data))
  {
    started_ = false;
    delete data; // or no delete?
    LOG_SYSFATAL << "Failed in pthread_create";
  }
}

int Thread::join()    //等待线程
{
  assert(started_);
  assert(!joined_);
  joined_ = true;
  return pthread_join(pthreadId_, NULL);
}

需要注意的是

1.在linux系统中,每个进程都有一个pid,类型pid_t,由getpid()取得。Linux下的POSIX线程也有一个id,类型pthread_t,由pthread_self()取得,该线程由线程库维护,其id空间是各个进程独立的(即不同线程中可能拥有相同的id)。有时我们需要知道线程的真实id,就不能使用pid和pthread id,需要使用该线程真实的id,称为tid。(不是我们平常所用的pthread_t tid; tid=pthread_create()的那个tid)。

linux系统中有一个系统调用可以实现得到线程的真实id,我们可以实现一个函数,返回该系统调用的返回值,return syscall(SYS_gettid),但是频繁系统调用会造成性能降低,muduo库就使用了全局变量current_tid来缓存它,我们只需要调用一次,以后直接获取该缓存就可以了。


2.__thread修饰的变量是线程局部存储的,每个线程都有一份。__thread,gcc内置的线程局部存储设施。__thread只能修饰POD类型。如果类没有定义构造函数,也是POD类型。


3.boost::is_same用来判断是否是同一类型

比如typedef unsigned int u_int,就是同一类型。


4.pthread_atfork()

int pthread_atfork(void (*prepare)(void), void(*parent)(void), void(*child)(void));

调用fork时,内部创建子进程前在父进程中会调用prepare,内部创建子进程成功后,父进程会调用parent,子进程会调用child。

示例:

#include <iostream>
#include <time.h>
#include <pthread.h>
#include <unistd.h>

using namespace std;

void prepare()
{
    cout<<"pid = "<<static_cast<int>(getpid())<<" prepare"<<endl;
}

void parent()
{
    cout<<"pid = "<<static_cast<int>(getpid())<<" parent"<<endl;
}

void child()
{
    cout<<"pid = "<<(static_cast<int>(getpid()))<<" child"<<endl;
}

int main()
{
    cout<<"pid = "<<(static_cast<int>(getpid()))<<" enntering main"<<endl;

    pthread_atfork(prepare, parent, child);

    fork();

    cout<<"pid = "<<(static_cast<int>(getpid()))<<" exiting main"<<endl;

    return 0;
}
输出:



5.多线程程序中调用fork()造成死锁示例

见我另一篇博客,这部分是我追加的:http://blog.youkuaiyun.com/freeelinux/article/details/53426876




GD32H7 SPI驱动实战:手把手教你用SPI3连接外部Flash(W25Q128)并实现读写 本文详细介绍了基于GD32H7系列MCU的SPI3接口驱动W25Q128外部Flash的全流程开发指南。从硬件设计、引脚配置到SPI3外设深度配置,再到底层通信函数实现和高级功能优化,提供了完整的解决方案。特别针对高速读取、DMA传输和信号完整性等关键环节进行了优化,确保系统在-40℃~85℃范围内稳定工作。 阅读详情

相关推荐

关于小样本学习综述论文的总结

对小样本学习综述的个人总结

qq_46176086的博客 5456

__thread关键字

__thread是GCC内置的线程局部存储设施,存取效率可以和全局变量相比。__thread变量每一个线程有一份独立实体,各个线程的值互不干扰。可以用来修饰那些带有全局性且值可能变,但是又不值得用全局变量保护的变量。        __thread使用规则:只能修饰POD类型(类似整型指针的标量,不带自定义的构造、拷贝、赋值、析构的类型,二进制内容可以任意复制memset,memcpy,且内容可

liuxuejiang158的专栏 2万+

The moving least square approximation(MLS).

移动最小二乘法, moving least square

fanglovel的博客 299

C++11并发之std::thread

std::thread 在 #include<thread> 头文件中声明,因此使用 std::thread 时需要包含 #include<thread> 头文件。

liuker的博客 2万+

S32K344 Flash Driver实战:手把手教你实现任意字节写入与扇区解锁(含C40_Ip避坑指南)

本文深入解析S32K344微控制器的Flash驱动开发,重点解决C40_Ip驱动库的8字节对齐限制和扇区保护锁问题。通过实战案例和代码示例,详细介绍了如何实现任意字节写入、扇区解锁及性能优化策略,为Bootloader和OTA升级等应用提供可靠解决方案。

weixin_33713707的博客 432

Fanuc机器人的坐标变换矩阵的研究2

一、Funuc用户坐标系的介绍 二、用户坐标系与世界坐标系的坐标转换 三、 以用户坐标系1为基础旋转变换后的用户坐标系 四、关于点的WPR的含义 4.1:点在用户坐标系和世界坐标系下的坐标关系 4.2 通过转换矩阵返回去推导WPR

qq_34047402的博客 1523

gcc __thread关键字

gcc __thread关键字Thread Local Storage 线程局部存储(tls)是一种机制,通过这一机制分配的变量,每个当前线程有一个该变量的实例.gcc用于实现tls的运行时模型最初来自于IA-64处理器的ABI,但以后被用到其它处理器上。它需要链接器(ld),动态连接器(ld.so)和系统库(libc.so,libpthread.so)的全力支持.因此它不是到处可用的。在用户层

谢健的专栏 1万+

Open3D点云数据处理(五):点云、mesh可视化(draw_geometries方法)

本文介绍了Open3D中的draw_geometries可视化方法,可以用于可视化点云和mesh。详细讲述了该方法的各个参数的作用,给出了代码示例。

孙悟空 3137

muduo学习笔记:base部分之CurrentThread命名空间与Thread类

muduo的Thread是pthread的封装,实现了线程的基本操作,已经CurrentThread命名空间有关线程id管理和优化。

热爱生活,忠于自己 1180

SDMA 如何实现设备对主机内存的访问

摘要:SDMA(System Direct Memory Access)是PCIe设备直接访问主机内存的核心机制,使外设无需CPU干预即可高效读写系统RAM。其实现原理包括:设备作为主控发起DMA请求,通过PCIe Memory TLP访问主机物理地址;完整通路涉及驱动分配DMA安全内存、设备配置、地址转换(IOMMU)和中断通知等步骤;关键技术涵盖地址类型(HPA/IOVA)、TLP格式、缓存一致性和安全防护机制。SDMA广泛应用于GPU、网卡、NVMe等高性能场景,是现代异构计算的基础技术,需软硬件协同

MHD0815的博客 240

API Streaming Failed 400 <400>InternalError.Algo.InvalidParameter input content must be a string解决方案

本文主要介绍了API Streaming Failed 400 <400> InternalError.Algo.InvalidParameter input content must be a string解决方案,希望能对使用vscode中cline的同学们有所帮助。 文章目录 1. 问题描述 2. 解决方案

weixin_43178406的博客 3万+

muduo源码学习base——Exception(带 stack trace 的异常基类)

元素 函数的返回值是实际返回的void。mangle 和 demangle。

qq_41420788的博客 462

【Bug已解决】Request timed out / API Timeout — Claude Code 请求超时解决方案

方案适用场景推荐指数难度方案一:增加超时大任务处理⭐⭐⭐⭐⭐低方案二:切换 SonnetOpus 太慢⭐⭐⭐⭐⭐低方案三:缩小范围大代码库⭐⭐⭐⭐⭐低方案四:优化网络网络延迟高⭐⭐⭐⭐中方案五:减少 MCPMCP 超时⭐⭐⭐中方案六:流式响应长生成任务⭐⭐⭐低根本原因:请求超时最常见原因是请求体过大(35%)和 Opus 模型推理慢(25%),默认 60 秒超时阈值对大型任务不够最佳实践。

一键难忘的博客 5161

[muduo网络库]——muduo库Thread类(剖析muduo网络库核心部分、设计思想)

muduo 是由陈硕大佬个人开发的 TCP 网络库,本专栏使用c++11重构了Muduo库中核心的Multi-Reactor架构,剖析大佬核心的代码设计思想,希望能够理清自己的思路,也希望能够帮助到大家。

m0_73537205的博客 558

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

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

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

Muduo库源码剖析(五)——Thread相关类

线程池若不自定义线程数,则所有工作都在唯一的。的一对一绑定,是muduo库的一大亮点。该类主要功能是线程池,每一条。该类的主要功能是实现。

qq_42120843的博客 253

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

Muduo库代码剖析 : ThreadPool

本章我们将把EventLoop和C++11的thread结合, 实现Thread / EventLoopThread / EventLoopThreadPool.

tianmu_sama的博客 1096

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

【Muduo源码剖析笔记】 基础组件之线程库

Muduo库源码阅读笔记

LeeEdgar的博客 217

muduo网络库剖析——线程Thread类

基于c++的muduo网络库开源项目深度剖析!超级加分的简历项目,期待您的讨论~

weixin_62021811的博客 1285

[muduo网络库]——muduo网络库精华总结(剖析muduo网络库核心部分、设计思想)

muduo 是由陈硕大佬个人开发的 TCP 网络库,本专栏使用c++11重构了Muduo库中核心的Multi-Reactor架构,剖析大佬核心的代码设计思想,希望能够理清自己的思路,也希望能够帮助到大家。

m0_73537205的博客 2826

[muduo网络库]——muduo库EventLoopThread类(剖析muduo网络库核心部分、设计思想)

muduo 是由陈硕大佬个人开发的 TCP 网络库,本专栏使用c++11重构了Muduo库中核心的Multi-Reactor架构,剖析大佬核心的代码设计思想,希望能够理清自己的思路,也希望能够帮助到大家。

m0_73537205的博客 888

[muduo网络库]——muduo库EventLoopThreadPool类(剖析muduo网络库核心部分、设计思想)

muduo 是由陈硕大佬个人开发的 TCP 网络库,本专栏使用c++11重构了Muduo库中核心的Multi-Reactor架构,剖析大佬核心的代码设计思想,希望能够理清自己的思路,也希望能够帮助到大家。

m0_73537205的博客 1210

muduo库的EventLoopThread类剖析

关于EventLoopThread有以下几点: 1.任何一个线程,只要创建并运行了EventLoop,都称之为I/O线程。 2.I/O线程不一定是主线程。I/O线程中可能有I/O线程池和计算线程池。 3.muduo并发模型one loop per thread + threadpool 4.为了方便使用,就直接定义了一个I/O线程的类,就是EventLoopThread类,该类实际上就是对

FreeeLinux's blog 1432

muduo源码剖析之AsyncLogging异步日志类

AsyncLogging是muduo的日志,程序如果直接让文件写日志可能会发生阻塞,muduo前端设计了2个BufferPtr,分别是currentBuffer_和nextBuffer_,还有一个存放BufferPtr的vector(buffers_)。多个前端线程往currentBuffer_写数据,currentBuffer_写满了将其放入buffers_,通知后端线程读。前端线程将currentBuffer_和nextBuffer_替换继续写currentBuffer_。

新法的博客 2128

muduo库的线程池ThreadPool剖析

EventLoopThreadPool也是派生自noncopyable, 其用于创建IO线程池,用于把TcpConnection分派到某个具体的EventLoop线程上。EventLoopThreadPool是TcpServer的成员,生命周期由后者控制。 EventLoop我们应该很熟悉,也就是整个muduo库的核心,就是Reactor模式当中的Dispatcher(事件分发器),具体至EventLoop章节进行详细分析。

Mr_scott_j的博客 492

解析muduo源码之 Thread.h & Thread.cc

摘要:本文详细解析了Muduo网络库中的Thread线程封装类实现。Thread类通过封装POSIX pthread接口,提供面向对象的线程管理功能,支持任意可调用对象作为线程函数。核心设计包括:使用std::function封装线程执行函数;通过CountDownLatch确保线程启动同步;区分pthread虚拟ID和内核真实tid;原子变量统计线程数;自动生成线程名便于调试;异常安全处理和资源自动释放。实现上采用ThreadData结构封装执行上下文,startThread函数桥接C风格接口,并通过pr

m0_62807361的博客 647

【muduo源码剖析】Thread/ThreadPool源码解析

Thread/ThreadPool源码解析

weixin_46272577的博客 780
上一篇: 利用backtrace函数打印函数调用栈
下一篇: muduo的Mutex类剖析
FreeeLinux
博客等级 码龄11年 421粉丝 356原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值