c++反射实现方案的选择

    由于c++原生不支持反射,绝大多数情况也不需要反射,但是有些时候比如在读取配置文件或者数据表,如果通过反射可以避免写大量的重复无用的代码,提高开发效率。因此需要 c++的反射的实现满足下面的条件

1 不需要一股脑给所有的类都加反射不需要也没有必要,可以选择性的给需要的类加反射,毕竟加了反射以后肯定会有性能的消耗,这是我不想看到的。

2 不要改变c++的编程习惯,用起来不要太复杂

3 尽可能在编译器完成反射的注册(非必选,运行时注册科已在启动的时候完成所有反射类的注册)

4 有比较全面的类型错误检测,防止反射类型发生错误

5 支持的类型要全,对于代码来说,支持99%的类型和没有支持是一样的,不仅要支持基本类型的反射还要支持对象和stl容器的反射,枚举等等

6 不要改变对象的内存结构,尤其是pod类型的对象,对于pod类型我可以用内存池,可以可以memcpy和memmov,如果改了对象的内存结构,会有诸多的问题

7 不要破坏类的声明结构,否则代码的可读性会变得很差

8 实现很干净,不要因为引入一个简单的反射库装了一堆的其他的没用过的库比如尤其是boost这种大库

通过一段时间的相关查阅发现现存的实现方案,列举下感觉上可以用的方案

一 给代码加标签然后用工具分析自动生成代码

    1 unreal引擎(实现在C++源文件中空的宏做标记,然后用UHT分析生成generated.h/.cpp文件)

UCLASS()
class HELLO_API UMyClass : public UObject
{
	GENERATED_BODY()
public:
	UPROPERTY(BlueprintReadWrite, Category = "Test")
	float Score;

	UFUNCTION(BlueprintCallable, Category = "Test")
	void CallableFuncTest();

	UFUNCTION(BlueprintNativeEvent, Category = "Test")
	void NativeFuncTest();

	UFUNCTION(BlueprintImplementableEvent, Category = "Test")
	void ImplementableFuncTest();
};

    2 qt图形界面库(利用基于moc(meta object compiler)实现,用一个元对象编译器在程序编译前,分析C++源文件,识别一些特殊的宏Q_OBJECT、Q_PROPERTY、Q_INVOKABLE……然后生成相应的moc文件,之后再一起全部编译链接)。

#include <QObject>
class MyClass : public QObject
{
    Q_OBJECT
  Q_PROPERTY(int Member1 READ Member1 WRITE setMember1 )
  Q_PROPERTY(int Member2 READ Member2 WRITE setMember2 )
  Q_PROPERTY(QString MEMBER3 READ Member3 WRITE setMember3 )
  public:
      explicit MyClass(QObject *parent = 0);
  signals:
  public slots:
  public:
    Q_INVOKABLE int Member1();
    Q_INVOKABLE int Member2();
    Q_INVOKABLE QString Member3();
    Q_INVOKABLE void setMember1( int mem1 );
    Q_INVOKABLE void setMember2( int mem2 );
    Q_INVOKABLE void setMember3( const QString& mem3 );
    Q_INVOKABLE int func( QString flag );
  private:
    int m_member1;
    int m_member2;
    QString m_member3;
 };

      这两个功能非常完善,使用起来非常简单优雅,都是简单的给类和相关的变量和函数加上标签,然后通过自己实现的工具分析代码生成先关的代码(对用户是透明的)不需要关系中间的复杂过程和生成的复杂代码,遗憾的是都需要基于各自的开发工具才能使用,我们不能直接使用。

    3  https://github.com/Leandros/metareflect ,Metareflect is a lightweight reflection system for C++, based on LLVM and Clangs libtooling.,一个类似于上面的一种解决方案,也是加标签然后分析代码的方式,不过使用方法略微复杂。

CLASS() Point
{
public:
    PROPERTY()
    int x;

    PROPERTY()
    int y;

    PROPERTY()
    int z;

    FUNCTION()
    size_t Hash() const
    {
        return x ^ y ^ z;
    }
};

二 通过宏定义或者额外的代码的方式手动注册记录反射信息

  4  https://github.com/garettbass/reflect ,easy reflection and serialization for C++17,破坏了类的声明结构,并且要支持c++17  

struct example_struct {
    // use the reflect_fields macro to declare reflected fields
    reflect_fields(
        ((int),i),
        ((float),f),
        ((std::string),s) // NOTE: no trailing comma here
    )
};

  5 https://github.com/skarupke/reflection,通过宏定义手动注册

using namespace metav3;
struct memcpy_speed_comparison
{
    float vec[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
    int i = 0;
    float f = 0.0f;

    template<typename Ar>
    void serialize(Ar & archive, int)
    {
        archive & vec;
        archive & i;
        archive & f;
    }
};

REFLECT_CLASS_START(memcpy_speed_comparison, 0)
    REFLECT_MEMBER(vec);
    REFLECT_MEMBER(i);
    REFLECT_MEMBER(f);
REFLECT_CLASS_END()

  6  https://github.com/skypjack/meta ,通过额外代码注册

meta::reflect<my_type>(hash("reflected"))
    .func<&my_type::static_function>(hash("static"))
    .func<&my_type::member_function>(hash("member"))
    .func<&free_function>(hash("free"));

7  https://www.codeproject.com/Articles/8712/AGM-LibReflection-A-reflection-library-for-C

class Base {
public:
    //needed so as that the class gets reflection capabilities
    CLASS(Base, NullClass);

    //a reflected property
    PROPERTY(int, length);

    //a reflected method
    METHOD(public, bool, processLength, (int l));

private:
    //a reflected field
    FIELD(private, int, m_length);

    //property getter
    int get_length() const {
        return m_length;
    }

    //property setter
    void set_length(int l) {
        m_length = l;
    }
};

  虽然说实现很简单吗,只有一个头文件很简洁,但是破坏了声明结构并且对于容器不支持,对于<>宏定义展开后,会编译报错 

8  https://github.com/billyquith/ponder

class Person
{
public:
     // constructor
    Person(const std::string& name)
        : m_name(name)
    {}

    // accessors for private members
    std::string name() const { return m_name; }
    void setName(const std::string& name) { m_name = name; }

    // public members
    float height;
    unsigned int shoeSize;

    // member function
    bool hasBigFeet() const { return shoeSize > 10; } // U.K.!

private:
    std::string m_name;
};
//! [eg_simple_class]

//! [eg_simple_declare]
PONDER_TYPE(Person)     // declare the type to Ponder

static void declare()   // declare the class members to Ponder
{
    ponder::Class::declare<Person>("Person")
        .constructor<std::string>()
        .property("name", &Person::name, &Person::setName)
        .property("height", &Person::height)
        .property("shoeSize", &Person::shoeSize)
        .function("hasBigFeet", &Person::hasBigFeet)
        ;
}

9  rttr

   官网地址:https://www.rttr.org/

   github地址:https://github.com/rttrorg/rttr

#include <rttr/registration>
using namespace rttr;

struct MyStruct { MyStruct() {}; void func(double) {}; int data; };

RTTR_REGISTRATION
{
    registration::class_<MyStruct>("MyStruct")
         .constructor<>()
         .property("data", &MyStruct::data)
         .method("func", &MyStruct::func);
}


type t = type::get<MyStruct>();
for (auto& prop : t.get_properties())
    std::cout << "name: " << prop.get_name() << std::endl;

for (auto& meth : t.get_methods())
    std::cout << "name: " << meth.get_name() << std::endl;

  以上是几种感觉还可的实现方案,但也不是全都能用1和2肯定用不了,3是可以用的(但是生成的代码的安全性没法保证),4和7破坏了类的声明结构不考虑了,5,6,8和9其实原理是一样的手动注册,然后就是分析源码我选择了rttr,他的github标星最多,有自己的官网,文档齐全。特性齐全:

1 反映构造函数,方法,数据成员或枚举
2 类; 具有单继承,多继承和虚拟继承
3 构造函数(任意参数计数)
4 方法(虚拟,抽象,重载,任意参数计数)
5 数组(包括原始数组;任意维数)
6 从任意类级别调用类的属性和方法的能力
7 无割台污染;在cpp文件中创建反射信息,以最大程度地减少修改数据时的编译时间
8 使用自定义类型,而无需在编译时声明类型(对插件有用)
9 向所有反射对象添加其他元数据的可能性
10 向方法或构造函数添加默认参数的可能性
11 通过政策调整注册行为
12 最小的宏使用
13 无需其他第三方依赖
14 无需 rtti;包含更快且跨共享库的工作替换
15 没有例外(此功能需要付费,并且在控制台上也经常禁用)
16 无需外部编译器或工具,仅需标准ISO C ++ 11

     使用简单,不破坏声明结构,没有依赖支持类型齐全,不破坏内存结构(pod类型),对于非pod类型如果需要检索类的继承关系图时需要在勒种加RTTR_ENABLE

struct A { RTTR_ENABLE() };
struct B : A { RTTR_ENABLE(A) };
struct C : B { RTTR_ENABLE(B) };
/************************************************************************************
*                                                                                   *
*   Copyright (c) 2014 - 2018 Axel Menzel <info@rttr.org>                           *
*                                                                                   *
*   This file is part of RTTR (Run Time Type Reflection)                            *
*   License: MIT License                                                            *
*                                                                                   *
*   Permission is hereby granted, free of charge, to any person obtaining           *
*   a copy of this software and associated documentation files (the "Software"),    *
*   to deal in the Software without restriction, including without limitation       *
*   the rights to use, copy, modify, merge, publish, distribute, sublicense,        *
*   and/or sell copies of the Software, and to permit persons to whom the           *
*   Software is furnished to do so, subject to the following conditions:            *
*                                                                                   *
*   The above copyright notice and this permission notice shall be included in      *
*   all copies or substantial portions of the Software.                             *
*                                                                                   *
*   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR      *
*   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,        *
*   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE     *
*   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER          *
*   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,   *
*   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE   *
*   SOFTWARE.                                                                       *
*                                                                                   *
*************************************************************************************/

#ifndef RTTR_RTTR_ENABLE_H_
#define RTTR_RTTR_ENABLE_H_

#include <type_traits>

#include "rttr/type.h"
#include "rttr/type_list.h"

#ifdef DOXYGEN

/*!
 * \brief This macro is necessary in order to retrieve type information about the
 *        inheritance graph of a class. When there is no inheritance graph, the macro is **not** needed, e.g. for POD types.
 *
 * Put the macro inside every class, where you need the complete inheritance information about the class type.
 *
 * \code{.cpp}
 * struct Base
 * {
 *   RTTR_ENABLE()
 * };
 * \endcode
 *
 * Place the macro \ref RTTR_ENABLE() somewhere in the class, it doesn't matter if its under the public,
 * protected or private class accessor section. The macro will close itself with a `private` visibility.
 * So when you not specify anything afterwords, everything will be `private`.
 *
 * Into the derived class you put the same macro, but now as argument the name of the parent class.
 * Which is in this case `Base`.
 * \code{.cpp}
 *   struct Derived : Base
 *   {
 *     RTTR_ENABLE(Base)
 *   };
 * \endcode
 *
 *  When you use multiple inheritance you simply separate every class with a comma.
 * \code{.cpp}
 *   struct MultipleDerived : Base, Other
 *   {
 *     RTTR_ENABLE(Base, Other)
 *   };
 * \endcode
 *
 * \remark Without this macro, it will not be possible to use \ref rttr::rttr_cast "rttr_cast" or
 *         meta information in the type class, like: \ref rttr::type::get_base_classes() "get_base_classes()" or
 *         \ref rttr::type::get_derived_classes() "get_derived_classes()".
 */
#define RTTR_ENABLE(...)

#else

#define TYPE_LIST(...)      ::rttr::type_list<__VA_ARGS__>

#define RTTR_ENABLE(...) \
public:\
RTTR_BEGIN_DISABLE_OVERRIDE_WARNING \
    virtual RTTR_INLINE ::rttr::type get_type() const { return ::rttr::detail::get_type_from_instance(this); }  \
    virtual RTTR_INLINE void* get_ptr() { return reinterpret_cast<void*>(this); } \
    virtual RTTR_INLINE ::rttr::detail::derived_info get_derived_info() { return {reinterpret_cast<void*>(this), ::rttr::detail::get_type_from_instance(this)}; } \
    using base_class_list = TYPE_LIST(__VA_ARGS__); \
RTTR_END_DISABLE_OVERRIDE_WARNING \
private:

#endif // DOXYGEN

#endif // RTTR_RTTR_ENABLE_H_

      它会给类的对象的内存头加一个虚函数表指针,当然如果类本身就有虚函数,也就有虚函数表,加一个虚函数,就不会出现这种情况,或者说如果你不需要检索类的继承图,仅仅反射对象的成员变量和成员函数,那也不需要这个宏定义,也不会修改类的内存结构,在这点上可以接受。

     唯一不足的是源代码大量运用了c++11和模版元编程,可以说把c++11和模版元编程发挥到了极致,读起来比较难懂容易偏头疼,不过在类型安全的检测上还是做得很到位的。

最后总的来说倾向于两个选择:

1 第三种 metareflect加标签的方式(用起来是最舒服的,也是最优雅的)

2 最后一种rttr,虽然用起来稍微麻烦点需要手动注册但是代码的可控性和安全性很高,个人比较倾向于这种。

参考链接:

  https://www.ctolib.com/mip/Cmdu76-AwesomeCppGameDev.html

  https://zhuanlan.zhihu.com/p/24445322

 

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
语音识别的MATLAB实现 声控小车结题报告 小组成员:关世勇 吴庆林 一、 项目要求: 声控小车是科大华为科技制作竞赛命题组的项目,其要求是编写一个语言识别程序并适当改装一个小型机动车,使之在一个预先不知道具体形状的跑道上完全由声控来完成行驶比赛。跑道上可以有坡面,坑, 障碍等多种不利条件,小车既要具有较快的速度,也要同时具有较强的灵活性,能够克服上述条件。 二、 项目分析: 由于小车只要求完成跑道上的声控行驶,所以我们可以使用简单的单音命令来操作,如“前”、“后”、“左”、“右”等。 由于路面有各种不利条件,而且规则要求小车尽可能不越过边线,这就决定了我们的小车不能以较高的速度进行长时间的快速行驶。所以我们必须控制小车的速度和行进距离。 由于外界存在噪声干扰,所以我们必须对噪声进行处理以减小其影响。 鉴于上诉各种要求,我们决定对购买的遥控小车进行简单改造,使用PC机已有的硬件条件编写软件来完成语音的输入,采集,处理和识别,以实现对小车的控制。 三、 解决思路与模块: 整个程序大致可划分为三个模块,其结构框图如下图所示: 整个程序我们在Visual C++ 环境下编写。 四、 各模块的实现: 1 声音的采集: 将声音信号送入计算机,我们利用了声卡录音的低层操作技术,即对winmm.lib进行API调用。具体编程时这一部分被写在一个类中(Soundin类)。 在构造函数中设定包括最大采样率(11025),数据缓存(作为程序一次性读入的数据,2048),声卡本身所带的一些影响采样数据等的各种参数; 调用API函数waveInGetNumDevs(返回UNIT,参数为空)检察并打开声音输入设备,即声卡;并进而使用waveInGetDevCaps得到声卡的容量(在waveInCaps中存有该数据,对其进行地址引用,从DWORD dwFormats得到最大采样率、声道数和采样位); 创建一个叫WaveInThreadEvent的事件对象,并赋予一个Handle,叫m_WaveInEvent,开始利用线程指针m_WaveInThread调用自定义的线程WaveInThreadProc; 对结构WAVEFORMATEX中WaveInOpen开始提供录音设备。注意设备句柄的得到是通过对HWAVEIN 型数据m_WaveIn的引用。 由于通过这种方式进行录音的文件格式是.wav,所以要先设置录音长度,以及对头文件进行一些设置:包括buffer的地址为InputBuffer的初始地址,大小为录音长度的两倍,类型。使用waveInPrepareHeader为录音设备准备buffer。然后使用waveInAddBuffer函数为录音设备送出一个输入buffer。最后使用waveInStart(m_WaveIn)打开设备。 程序中WaveInThreadProc需要提出另外说明,因为通过这个线程我们可以实现采样和数据提取。该线程首先定义一个指向CsoundIn类的指针pParam,并将其宏定义为PT_S。而线程参数即为空指针pParam。使用WaitForSingleObject将录音过程设置为一旦开始就不中止(除非中止线程)。在此线程中做如下两个工作:将数据送入buffer,并将数据传入某个参数(其调用一个函数,将buffer中的数据送入该函数的参数*pt),而这些数据正是我们要利用和处理的数字化的语音信息。 2 声音的预处理: 声音信息的预处理主要包括音头和音尾的判断,声音的预加重,分帧处理和窗化处理。 A 音头音尾的判断与提取: 这是该项目的一个难点。由于我们的声音信号不是连续给出的,而且现场还有噪声的存在,所以我们必须通过适当的方法来判断采集的数据是不是我们所要的声音控制信号。这又是该项目的一个重点。若声音指令信号提取的不恰当,那么我们采样所得的数据就和我们实际的语音信号就会有很大的出入,这样不但会延迟语音识别的时效性,而且会降低对这些声音信号的识别率。对声音信号的提取,主就是确定音头、音尾的位置。常用的方法有过零率和短时距能量等几种。我们这里采用的就是过零率这个方法。首先对噪声取样,从这些噪声样本中得到噪声的上下限,将实时信号与这个门限进行比较,得到过零率。 定义过零率Zcr如下: 其中: 利用过零率的大小来判断是否有声音信号进入,若 ( 为预设的过零率值),则表示有声音信号进入,就找到了音头。在找到音头的情况下,若 ,则表示声音结束,也就找到了音尾。在环境噪声较大且比声音指令小的多的情况下可以对这个门限加一修正。音头和音尾之间的部分就是我们用以作为识别用的声音指令信号了。由于一般情况下人们所发出的单音都有一定的时间长度而大的噪声则大多是突发的,持续时间较短,所以我们可以再对所得到的声音指令信号做一次筛选,若得到的声音信号的长度小于预设值,就可认为是噪声干扰,舍弃;若得到的声音信号的常到大于预设值,则将其作为有用信号存储。实验表明,利用过零率和预设长度相结合起来提取声音指令信号的方法很有效的。 B 语音信号的预加重: 我们所采用的预加重的方法是较为常用的网络: 传递函数为: 得到的信号为: 预加重的目的在于滤除低频干扰,尤其是50Hz或60Hz的工频干扰,将对于语音识别更为有用的高频部分的频谱进一步提升。在计算短时能量之前应用该滤波器,还可以起到消除直流漂移、抑制随机噪声和提升清音部分能量的效果。 C 分帧处理 在计算各个系数之前要先将语音信号作分帧处理。语音信号是瞬时变化的,但在10~20ms内是相对稳定的,而我们设定的采样频率为11025所以我们对预处理后的语音信号S1(n)以300点为一帧进行处理,帧移为100个采样点。 (N=300) D 窗化处理: 为了避免矩形窗化时对LPC系数在端点的误差,我们采用了汉明窗函数来进行窗化。即: 其中: 3 语音数据的特征提取: 语音信号的特征有多种度量标准,我们采用的是比较常用的倒谱特征。 语音信号是一种典型的时变信号,然而如果把观察时间缩短到几十毫秒,则可以得到一系列近似稳定的信号。人的发音器官可以用若干段前后连接的声管进行模拟,这就是所谓的声管模型。全极点线性预测模型(LPC)可以对声管模型进行很好的描述,每段声管对应一个LPC模型的极点。一般情况下,极点的个数在12-16个之间就可以足够清晰地描述语音信号的特征了。 语音信号经过预处理,它的每个样值均可由过去若干个样值的线性组合来逼近,同时可以采用使实际语音抽样与线性预测抽样之间的均方差最小的方式,来解出一组预测的系数 。这就是LPC所提取出来的信号的初始特征。 预测值时域表达式为: 其中, 为加权系数,即LPC系数。预测的误差为: 使 在均方误差最小的条件下,可求得唯一的 ,此过程即为LPC分析过程。 这里采用的是Levinson-Durbin法。由上面的式子有: 其中, 为待分析与引信号的自相关序列: 因此:Levinson-Durbin算法为: 1. 初始化: 2. 迭代计算:对于 3. 最后就算: 以上式中的 为反射系数。 ; 为最小预测误差,随着阶数的增加而减少; 为模型增益常量。 在语音识别系统中,很少直接使用LPC系数,而是由LPC系数推导出另一种参数:线性预测倒谱系数(LPCC)。倒谱实际上是一种同态信号处理方法,标准的倒谱系数计算流程需要进行FFT变换、对数操作和相位校正等步骤,预算比较复杂。在实际计算中,他不是由原始信号x(n)得到,而是由LPC系数 得到的。 LPC系数算出后,就可以直接进行倒谱系数 的计算,其迭代算法如下: 1.初始化: 2.迭代计算: 这里C(0)实际上就是直流分量,在识别中通常是不用的,也不去计算。 综合考虑识别误差和识别速度的影响,我们在计算LPC 时,LPC系数的阶数Q值取为8,而LPCC系数的阶数P值取为12。 4 DTW 算法: 语音识别程序的核心部分即采用合适的算法来识别不同的语音信号,在特定人语音识别算法中,对于孤立词语语音识别而言,最为简单的方法是采用DTW(Dynamic Time Warping,动态时间弯折)算法,该算法基于动态规划)(DP)的思想,解决了发音长短不一的模本匹配问题,是语音识别中出现较早、较为经典的一种算法。我们这里采用的就是DTW算法。 我们用R表示已存的参考模板,T表示待识别的测试模板,R(1),R(2) ,…,R(m),T(1),T(2),…,T(n)分别表示参考模板和测试模板中的各语音帧,d[T(n),R(m)]表示这两帧特征矢量之间的距离(DTW算法中通常采用欧氏距离)。为了比较R和T之间的相似度,可以计算他们之间的距离D[T,R],距离越小则相似度越高。D[T,R]的计算通常采用的是动态规划的方法。 将R和T的各个帧号分别在直角坐标系的横轴和纵轴上标出,则如下图可得到一个网格,网格中各点表示R和T中的一帧的交汇点。DP算法可以归结为寻找一条通过此网格中若干格点的路径,使得沿路径的累积距离达到最小值。 为了使路径不至于过分倾斜,可以约束斜率在0.5-2范围内,如果路径已经通过了格点( ),那么下一个通过的格点( )只能是下列三种情况之一: 搜索最佳路径的方法如下: 搜索从( )开始,网格中任意一点只可能有一条路径通过。对于( ),其可达到该格点的前一格点之可能是 ( ),( ),( ),那么( )一定选择这3个距离中的最小者所对应的格点作为其前续格点。若用( )代表此格点,并将通过该格点的路径延伸而通过( ),这时此路径的累积距离为: 其中的 由下式决定: 这样可以从初始点出发依次搜索直到搜索到终点 便可得到最佳路径。 五、整个系统的软件流程图: 见右图。 六、硬件 用四个c1108型三极管来控制小车遥控手柄的前、后、左、右触点的通断。从计算机的并口引出四根信号线,与三极管相连,与前、后、左、右一一对应。若判断出指令信号后,则相应的信号线上输出高电平,该电路导通,发送无线信号。若无指令,则信号线上输出低电平,电路断路,不发送无线信号。电路示意图如下:(由于四条线路基本是一致的,这里只画出了其中的一根信号线与外电路的连接示意图) 七、实现功能与技术指标: 1. 软件上可以识别前、后、左、右、停等语音指令,并发出相应的控制信号。 2. 硬件上可以实时的收发无限信号,并控制小 车作相应的动作。 3. 语音识别正确率大于95%,从发出语音指令 到执行该指令的延时小于100ms。 八、与原设计方案的比较: 我们的整个方案基本是按照原设计方案来进行的,各项指标也基本达到了预定目标。 九、经费使用情况: 主要分为两部分: 第一, 由于我们都没有学过语音识别方面的知识,所以一开始我们就买了一些参考书和资料。 第二, 在软件部分初步成型后,在对小车进行改装时购买了一些电子元器件以及其他一些工具。 十、致谢: 感谢华为研究所为我们提供这样好的锻炼机会,我们从中学到了很多书本上学不到的知识。 感谢铁伟涛同学为我们提供方案支持。 感谢我的导师魏衡华老师和314实验室的所有负责人为我们提供PC机和其它硬件条件以及方便的实验环境。 感谢所有的评委老师在开题和中期评审中给我们提供很多宝贵的意见。
《Linux多线程服务端编程:使用muduo C++网络》主要讲述采用现代C++在x86-64 Linux上编写多线程TCP网络服务程序的主流常规技术,重点讲解一种适应性较强的多线程服务器的编程模型,即one loop per thread。 目 录 第1部分C++ 多线程系统编程 第1章线程安全的对象生命期管理3 1.1当析构函数遇到多线程. . . . . . . . . . . . . . . . .. . . . . . . . . . . 3 1.1.1线程安全的定义. . . . . . . . . . . . . . . . .. . . . . . . . . . . 4 1.1.2MutexLock 与MutexLockGuard. . . . . . . . . . . . . . . . . . . . 4 1.1.3一个线程安全的Counter 示例.. . . . . . . . . . . . . . . . . . . 4 1.2对象的创建很简单. . . . . . . . . . . . . . . . .. . . . . . . . . . . . . . 5 1.3销毁太难. . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . . . . . 7 1.3.1mutex 不是办法. . . . . . . . . . . . . . . . . . . .. . . . . . . . 7 1.3.2作为数据成员的mutex 不能保护析构.. . . . . . . . . . . . . . 8 1.4线程安全的Observer 有多难.. . . . . . . . . . . . . . . . . . . . . . . . 8 1.5原始指针有何不妥. . . . . . . . . . . . . . . . .. . . . . . . . . . . . . . 11 1.6神器shared_ptr/weak_ptr . . . . . . . . . .. . . . . . . . . . . . . . . . 13 1.7插曲:系统地避免各种指针错误. . . . . . . . . . . . . . . . .. . . . . . 14 1.8应用到Observer 上.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16 1.9再论shared_ptr 的线程安全.. . . . . . . . . . . . . . . . . . . . . . . . 17 1.10shared_ptr 技术与陷阱. . . .. . . . . . . . . . . . . . . . . . . . . . . . 19 1.11对象池. . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . . . . . . 21 1.11.1enable_shared_from_this . . . . . . . . . . . . . . . . . . . . . . 23 1.11.2弱回调. . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . . 24 1.12替代方案. . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . . . . . 26 1.13心得与小结. . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . . . . 26 1.14Observer 之谬. . . .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28 第2章线程同步精要 2.1互斥器(mutex). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32 2.1.1只使用非递归的mutex . . . . . . . . . . . . . .. . . . . . . . . . 33 2.1.2死锁. . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . . . 35 2.2条件变量(condition variable). . . . . . . . . .

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值