笔记草稿。

#include <iostream>
#include ".. estalS_utinity.h"
#include <list>
#include <vector>
#include "stdio.h"
#include <map>

//代理类,可以默认,就可以用对象数组,成员为指针,可以为0.有copy3件套.代理行为,检测0,
//什么时候需要写继承.感觉应该必须满足一个条件.就是需要多态.如果不需要多态.就算是is a,关系.也没有必要非整出一个基类.
//只要继承,就会使用指针来表示多态.只要有指针,就必须用代理类.
//所以只要继承就必须代理.

using namespace std;


class vehicle
{
public:
virtual double weight()=0;
virtual void start()=0;
};

class bike:public vehicle
{
public:
double weight();
void start();
};

class bus:public vehicle
{
public:
double weight();
void start();
};

class car:public vehicle
{
public:
double weight();
void start();
};

double bike::weight()
{
return 200;
}
void bike::start()
{

}

double bus::weight()
{
return 2000;
}
void bus::start()
{

}


double car::weight()
{
return 400;
}
void car::start()
{

}

class pm
{
public:
pm(vehicle*);
vehicle* getP();
~pm();
private:
pm();
pm(const pm&);
pm operator=(const pm&);
vehicle * pveh;
};

pm::pm(vehicle* _p):pveh(_p){}
pm::~pm(){delete pveh;}
vehicle* pm::getP(){return pveh;}


//一,对于单资源(狭义上就是内存,再狭义就是堆内存)的使用和管理.
//1,资源的建立和托管必须是一个步骤.2)托管对象必须保证和资源同生死.
//对于栈内存,.bike mybike1; 对于堆内存.bike * mybike2=new bike();
//第一种,很可靠.
//第二种,需要显示维护内存,和保护指针变量.所以引出一条款(effect c++),用对象管理资源.
//而资源管理对象和资源同生死.就必须保证资源建立和对象建立是原子操作.也是另一条款.
//并且资管,由于资源入对象是原操,那么资管必须负责资源的delete.
//1)资管必须负责资源的delete.
//2)负责delete,也就必须考虑资源copy三函数,构造,赋值,析构.
//3)资管可以没有默认的构造函数,
//4)可以直接用方法提供只读的资源地址,供外部使用
//对于第2条.如果是资源地址copy.资管转化为智能指针类.
//如果是资源copy.提供正确的构造,赋值,析构.
//如果是禁止资源copy,构造,赋值,析构.设置为private.
//如果是资源转移.提供正确的构造,赋值,析构.


//所以最终对于单资源的资源的使用.在c++中有2种比较可靠的方法.
//1)栈内存, bike mybike1;
//2)堆内存,pm mypm(new bike());

//对于多资源的统一使用和管理.
//基本是对于含有继承关系的对象而言.没有继承关系,谈不上统一管理.
//那么必须是管理指针.参考上面分析.必须建立对象.
//那么必须要求资源有默认的构造函数.

void showWeight(vehicle * _p)
{
cout<<_p->weight()<<endl;
}

int main()
{
//地址copy,使用智能指针类.
bike mybike1;
cout<<"**auto p***"<<endl;
showWeight(&mybike1);

//地址copy,使用智能指针类.
cout<<"**copy p***"<<endl;
pm_copyP<bike> mypm(new bike());
pm_copyP<bike> mypm2=mypm;
pm_copyP<bike> mypm3(new bike());
mypm3=mypm;

showWeight(mypm.getP());
showWeight(mypm2.getP());
showWeight(mypm3.getP());

//禁止copy值或地址.使用禁止类.
cout<<"**forbiden***"<<endl;
pm_forbidP<bike> mypm4(new bike());
showWeight(mypm4.getP());
//pm_forbidP<bike> mypm5=mypm4;//禁止复制,赋值.

//value copy,使用value-copy类.
cout<<"**copy value***"<<endl;
pm_copyValue<bike> mypm5(new bike());
pm_copyValue<bike> mypm6=mypm5;
pm_copyValue<bike> mypm7(new bike());
mypm7=mypm5;

showWeight(mypm5.getP());
showWeight(mypm6.getP());
showWeight(mypm7.getP());

//转移资源所有权, 使用transforP类. 这个和其他有不同.使用指针必须先判断,指针是否已经转移,为0了.
cout<<"**transforP***"<<endl;
pm_transforP<bike> mypm8(new bike());
pm_transforP<bike> mypm9=mypm8;
pm_transforP<bike> mypm10(new bike());
mypm10=mypm8;

if(mypm8.getP()!=0)
{
showWeight(mypm8.getP());
}
if(mypm9.getP()!=0)
{
showWeight(mypm9.getP());
}
if(mypm10.getP()!=0)
{
showWeight(mypm10.getP());
}

// vehicle* allCar[100]={0};
//
// bike mybike1;
// bus mybus1;
// car mycar1;
//
// allCar[0]=&mybike1;//这里是函数内,如果是外部参数,那么会有悬指针问题.所以条款,对象管理资源很必要.
// allCar[1]=&mybus1;
// allCar[2]=new car;//这里必须管理内存.
//
//
// for(int i=0;i!=100;++i)
// {
// if(allCar[i]!=0)
// {
// cout<< allCar[i]->weight()<<endl;
// }
// }

return 0;
}

#ifndef LS_UTINITY_H_INCLUDED
#define LS_UTINITY_H_INCLUDED

#include <iostream>
#include <list>
#include <vector>

using namespace std;

//智能指针
template<typename T>
class auto_MyP
{
public:
    auto_MyP<T>();
    auto_MyP<T>(T const* _p);
    auto_MyP<T>(const auto_MyP&);
    auto_MyP<T>& operator=(const auto_MyP&);
    T* getP()const;
    ~auto_MyP<T>();
    void del();
private:

    int * count_ref;
    const T* autop;
};

template<typename T>
auto_MyP<T>::auto_MyP()
{
    autop=0x0;
    count_ref=new int(1);
}

template<typename T>
auto_MyP<T>::auto_MyP(T const* _p)
{
    cout<<"p con:"<<_p<<endl;
    autop=_p;
    count_ref=new int(1);
}


template<typename T>
auto_MyP<T>::auto_MyP(const auto_MyP& _lht)
{
    autop=_lht.autop;
    ++(*_lht.count_ref);
    count_ref=_lht.count_ref;
}

template<typename T>
auto_MyP<T>& auto_MyP<T>::operator=(const auto_MyP& _lht)
{
    if(this!=&_lht)
    {
        del();
        this->autop=_lht.autop;
        *_lht.count_ref=*_lht.count_ref+1;
        this->count_ref=_lht.count_ref;
    }
    return *this;
}

template<typename T>
auto_MyP<T>::~auto_MyP()
{
    del();
}

template<typename T>
void auto_MyP<T>:: del()
{
    cout<<"false del:"<<*(this->count_ref)<<". add"<<autop<<endl;
    *(this->count_ref)=*(this->count_ref)-1;//前后自增加,就是此语句取值是取+1变量,还是把+1给临时变量,取值去取未+1的符号变量.

    if(*(this->count_ref)==0)
    {
        cout<<"del:"<<autop<<endl;
        //if(autop!=0x0)
        //{
            delete autop;
        //}
    }
}

template<typename T>
T* auto_MyP<T>::getP()const
{
    return  const_cast<T*>(autop);
}



//Merge sort
template<typename T>
list<T> mergeSort(const list<T>& source);

template<typename T>
list<T> mergeSort(const list<T>& source)
{
    list<T> ret;

    if(source.size()==1)
    {
        ret=source;
    }
    else if(source.size()==2)
    {
        typename list<T>::const_iterator firstit=source.begin();
        T firstvalue=*firstit;
        typename list<T>::const_iterator secondit=++firstit;
        T secondvalue=*secondit;

        if(firstvalue<=secondvalue)
        {
            ret=source;
        }
        else
        {
            ret.push_back(secondvalue);
            ret.push_back(firstvalue);
        }

    }
    else
    {
        unsigned int count_list=source.size();
        unsigned int modN= count_list%2;
        unsigned int subret=count_list/2;

        typename list<T>::const_iterator it=source.begin();

        list<T> leftS;
        list<T> rightS;

        for(int i=0;i!=subret+modN;++i)
        {
            leftS.push_back(*it);
            ++it;
        }

        for(int i=0;i!=subret;++i)
        {
            rightS.push_back(*it);
            ++it;
        }

        leftS=mergeSort(leftS);//lefts 传递const 引用,效率和安全,不会改动.返回对象.lefts被copy赋值函数处理.
        rightS=mergeSort(rightS);

        typename list<T>::const_iterator lefttop=leftS.begin();
        typename list<T>::const_iterator righttop=rightS.begin();

        while(lefttop!=leftS.end() || righttop!=rightS.end())
        {
            // check each top
            if(*lefttop<=*righttop)
            {
                ret.push_back(*lefttop);
                ++lefttop;
            }
            else
            {
                ret.push_back(*righttop);
                ++righttop;
            }
        }
        if(lefttop!=leftS.end())
        {
            //push no process data
            for(lefttop;lefttop!=leftS.end();++lefttop)
            {
                ret.push_back(*lefttop);
            }
        }
        else if(righttop!=rightS.end())
        {
            for(righttop;righttop!=rightS.end();++righttop)
            {
                ret.push_back(*righttop);
            }
        }
        return ret;
    }



    return ret;
}


//
template<typename T>
void quickSort(vector<T>& source, int startIndex, int endIndex)
{
    if(startIndex<endIndex)
    {
        int centerIndex=startIndex;
        for( int i=startIndex+1;i!=endIndex+1;++i)
        {
            if(source[i]<source[centerIndex])
            {
                T tempT=source[i];
                for( int j=i-1;j!=centerIndex-1;--j)
                {
                    source[j+1]=source[j];
                }
                source[centerIndex]=tempT;
                ++centerIndex;
            }
        }
        quickSort(source,startIndex,centerIndex-1);
        quickSort(source,centerIndex+1,endIndex);
    }
}


template<typename T>
int centerFind(const vector<T>& source,const T& finder)
{
    int ret=-2;
    int startIndex=0;
    int endIndex=source.size()-1;
    int CenterIndex=startIndex+(endIndex-startIndex)/2;

    while(ret==-2)
    {
        if(CenterIndex==startIndex&&startIndex==endIndex)//1个数
        {
            if(source[CenterIndex]==finder)
            {
                ret=CenterIndex;
            }
            else
            {
                ret=-1;
            }
        }
        else
        {
            if(source[CenterIndex]==finder)
            {
                ret=CenterIndex;
            }
            else if(source[CenterIndex]>finder)
            {
                endIndex=CenterIndex-1;
                CenterIndex=startIndex+(endIndex-startIndex)/2;
                if(startIndex>endIndex)
                {
                    ret=-2;
                }
            }
            else
            {
                startIndex=CenterIndex+1;
                CenterIndex=startIndex+(endIndex-startIndex)/2;
                if(startIndex>endIndex)
                {
                    ret=-2;
                }
            }
        }
    }
    return ret;
}

template<typename T>
class pm_copyP{
public:
    pm_copyP(T* _p);
    pm_copyP(const pm_copyP&);
    pm_copyP& operator=(const pm_copyP&);
    ~pm_copyP();
    T* getP();
private:
    pm_copyP();
    T* myp;
    int * count_ref;
    del();
};

template<typename T>
pm_copyP<T>::pm_copyP(T* _p):myp(_p),count_ref(new int(1)){}

template<typename T>
pm_copyP<T>::pm_copyP(const pm_copyP& _pm)
{
    myp=_pm.myp;
    count_ref=_pm.count_ref;
    ++(*count_ref);
}

template<typename T>
pm_copyP<T>& pm_copyP<T>::operator=(const pm_copyP& _pm)
{
    if(&_pm!=this)
    {
        del();
        myp=_pm.myp;
        count_ref=_pm.count_ref;
        ++(*count_ref);
    }
    return *this;
}

template<typename T>
pm_copyP<T>::~pm_copyP()
{
    del();
}

template<typename T>
pm_copyP<T>::del()
{
    --(*count_ref);
    if(*count_ref==0)
    {
        delete myp;
        delete count_ref;
    }
}

template<typename T>
T* pm_copyP<T>::getP()
{
    return myp;
}


template<typename T>
class pm_forbidP{
public:
    pm_forbidP(T* _p);
    ~pm_forbidP();
    T* getP();
private:
    T* myp;
    pm_forbidP();
    pm_forbidP(const pm_forbidP&);
    pm_forbidP& operator=(const pm_forbidP&);
};


template<typename T>
pm_forbidP<T>::pm_forbidP(T* _p):myp(_p){}


template<typename T>
T* pm_forbidP<T>::getP()
{
    return myp;
}

template<typename T>
pm_forbidP<T>::~pm_forbidP()
{
    delete myp;
}


template<typename T>
class pm_copyValue{
public:
    pm_copyValue(T* _p);
    pm_copyValue(const pm_copyValue&);
    pm_copyValue& operator=(const pm_copyValue&);
    ~pm_copyValue();
    T* getP();
private:
    T* myp;
    void del();
    pm_copyValue();
};

template<typename T>
pm_copyValue<T>::pm_copyValue(T* _p):myp(_p){}

template<typename T>
pm_copyValue<T>::pm_copyValue(const pm_copyValue& _pm):myp(new T(*_pm.myp)){}

template<typename T>
pm_copyValue<T>& pm_copyValue<T>::operator=(const pm_copyValue& _pm)
{
    if(&_pm!=this)
    {
        del();
        myp=new T(*_pm.myp);
    }
    return *this;
}

template<typename T>
pm_copyValue<T>::~pm_copyValue()
{
    del();
}

template<typename T>
void pm_copyValue<T>::del()
{
    delete myp;
}

template<typename T>
T* pm_copyValue<T>::getP()
{
    return myp;
}



template<typename T>
class pm_transforP{
public:
    pm_transforP(T* _p);
    pm_transforP(pm_transforP&);
    pm_transforP& operator=(pm_transforP&);
    ~pm_transforP();
    T* getP();
private:
    T* myp;
    void del();
    pm_transforP();
};

template<typename T>
pm_transforP<T>::pm_transforP(T* _p):myp(_p){}

template<typename T>
pm_transforP<T>::pm_transforP(pm_transforP& _pm):myp(_pm.myp)
{
    _pm.myp=0;//const 怎么可以修改.
}


template<typename T>
pm_transforP<T>& pm_transforP<T>::operator=(pm_transforP& _pm)
{
    if(this!=&_pm)
    {
        del();
        myp=_pm.myp;
        _pm.myp=0;//const 怎么可以修改.
    }
    return *this;
}

template<typename T>
pm_transforP<T>::~pm_transforP()
{
    del();
}

template<typename T>
void pm_transforP<T>::del()
{
    if(myp!=0)
    {
        delete myp;
    }
}

template<typename T>
T* pm_transforP<T>::getP()
{
    return myp;
}

#endif // LS_UTINITY_H_INCLUDED



关于异常:

#include <iostream>
#include <stdexcept>

using namespace std;
//c++,实在经验不足.感觉只能是,使用某些函数,又不想每次都检测是否返回正确.那么抛出错误.程序结束.
//感觉还不如返回错误代码呢.

int dev(int a,int b);

int main()
{
    int result=0;
    try
    {
        result=dev(3,1);
    }
    catch(exception &e)
    {
        //提示错误,保存关键数据,程序退出
        cout<<e.what()<<endl;
        return -1;
    }
    cout<<result<<endl;


    return 0;
}

int dev(int a,int b)
{
    if(b==0)
    {
        throw runtime_error("b is zero");
    }
    else if(b==1)
    {
        throw logic_error("b can not be 1");
    }
    else
    {
        return a/b;
    }
    return 0;
}

 关于类的数据成员和参数问题。以及const。

1)类的data member.
如果是内置类型或类的值类型,语义就是局部数据,const语义就是,在类内,一个局部常量.
如果是内置类型或类的指针或引用类型,语义就是局部的指针,指向外部数据,const语义就是,在类内,不可通过此指针修改外部数据.
如果是内置类型或类的智能指针类型.语义就是局部数据,但里面有指针指向外部数据.const语义就是,在类内,不可通过此局部数据中的指针修改外部数据.
(可以完全代替第二种,只是size为8,而第2中size是4(32system)).
如果是内置类型或类的智能指针的指针或引用类型.语义就是很大概率是你想的的太复杂了.请退化为第3种.智能指针就是为了自动释放内存.
再保存它的指针,又把问题解决方案变成了问题本身.餐巾纸的作用就是为了吃饭时,让衣服更干净.为了方便拿东西.又套一个外套,还不如拿掉餐巾纸.
但是构造函数的参数应该使用 智能指针的reference,这个时候智能指针当成一般类处理.智能指针本质就是一个类了.

总结:
值还是智能指针(指针),还是引用.
从数据库讲,

一个字段不是另一个表的key。那么就是值。否则就是引用。如果表不存在这个字读。那么就是用方法返回数据(查询其他表)

const还是非const?
可修改用非const.否则用const.
对于智能指针,指针不可修改用 const shared_ptr<T>,指针所指的数据不可修改用shared_ptr<const T>.

从数据库讲。如果一个字段设置了触发器,字段是只读了。那么类中。一定要是const。


2)类的constructor的参数.
如果参数是内置类型或类的值类型,语义就是会创建一个原数据的副本,压入函数体.const语义就是,此参数的数据不可修改.但可以赋值给const或非const.
如果参数是内置类型或类的指针或引用类型,语义就是引用原数据,压入原数据的指针到函数体.const语义就是此地址的指向不可修改.
如果参数是内置类型或类的智能指针类型.语义就是会创建一个原数据(包含一个指针)的副本,压入函数体.const语义就是,此参数的数据不可修改.也就是里面的地址的指向不可修改.

时钟周期
 
       时钟周期也称为振荡周期,定义为时钟脉冲的倒数(时钟周期就是单片机外接晶振的倒数,例如12M的晶振,它的时钟周期就是1/12us),是计算机中的最基本的、最小的时间单位。
       在一个时钟周期内,CPU仅完成一个最基本的动作。时钟脉冲是计算机的基本工作脉冲,控制着计算机的工作节奏。时钟频率越高,工作速度就越快。
 
       8051单片机把一个时钟周期定义为一个节拍(用P表示),二个节拍定义为一个状态周期(用S表示)。

机器周期
 
       计算机中,常把一条指令的执行过程划分为若干个阶段,每一个阶段完成一项工作。每一项工作称为一个基本操作,完成一个基本操作所需要的时间称为机器周期。8051系列单片机的一个机器周期由6个S周期(状态周期)组成。 一个S周期=2个节拍(P),所以8051单片机的一个机器周期=6个状态周期=12个时钟周期。
 
       例如外接24M晶振的单片机,他的一个机器周期=12/24M 秒;

指令周期
 

    执行一条指令所需要的时间,一般由若干个机器周期组成。指令不同,所需的机器周期也不同。

int main(void)
{
char buf[10];
int n = read(STDIN_FILENO, buf, 10);
write(STDOUT_FILENO, buf, n);
return 0;
}

输入字符,回车后。。。。。

少于等于10个ok。大于10个。后续的字符,和回车键都还在标准输出中,会认为用户敲入了命令。

 关于开发整体流程。

//对于开发的流程,个人倾向,先建模,后建表.再实际建立class.
//因为先建立表,可以更快理清类之前细节.因为建类的时候需要考虑实际数据的存放问题.
//建立类的时候,发现问题.也可以修改表.
//而建立好类,不满足表,改类就麻烦.
//再次.表的话更直观,可以先不考虑细节.从整体掌握模型的数据流是否正确.
//甚至,类中犯的错误的设计,在表中就不太会出现.如员工,和职务.表明显会有好几个.一个员工表,几个不同职务表.
//而类,可能会设计为一个类.建模错误,会导致表设计不符合表设计范式.
//但是设计表的时候也可以考虑一下类.是否需要多一个表,来表现包含关系.或继承关系.

再一次卡在设计流程上了。

继续卡在无数据库设计上。

有数据库设计,数据存放问题不用考虑。而无数据库,放在那里,用 vector 对象还是指针,总是感觉设计不好。用vector或智能指针。

应该还是基于分析后。关系型数据设计开路(好理解,也很熟悉),数据存放问题的话。去掉表的外键,放入外键所在的表。用vector直接存放对象。,vector自己离开作用域会自动析构。析构会调用成员的析构函数并释放堆空间。完美啊。

可以先省去内部中其他类的集合。从上往下设计下来就好,下级设计好了。再返回上级,使用下级的初始化函数,来修改上级的初始化函数或其它初始化的地方。

这样设计了数据的流向后,再从面向对象的思维,设计行为。来给数据流向取个名字。

对象间的数据存放问题。

1)如果原本数据成员都不多。那么偏向一方(其中有确定数据属于的那方)。

2)用map存储数据。类方法提供对map的真删改,查, 类本身或管理类提供逻辑,调用增删改,特别注意逻辑中含删除的操作。

单个数据直接放栈,如果太大用智能指针。如果是不确定的多个数据或者多个大数据。用vector就好了。甚至单个大数据也可以用vector,vector自己离开作用域会自动析构。析构会调用成员的析构函数并释放堆空间。完美啊。

定义参数值用全局const。但如果是状态返回值或者作为参数可以用enum.这样就可以限定返回的数据范围。但是枚举不能设定数据类型。比如int_8,所以在网络编程需要固定长度的时候又很尴尬。

模型设计的一点想法,

看了下网狐。有个设计,类之间的包含关系 ,不放指针,或智能指针。

直接放一个key.

所以设计的时候,

1.可以先设计一个对象,包含属性和方法。

2.再设计一个管理类,包含一个当前key 的最大小(根据情况,是先进先出,还是先进后出)值。 用int 记录。

一般可以用int ,取int最大值为默认值,表示下次插入的key。插入的时候用这个做key.并·--,  删除的时候,看看要删除的是不是等于 key-1.如果是,++。 所以用map的key,来当前数据库的外键。

好处是避免了指针的坏处。指针可能有移动操作,也比较危险。而用 key,自然的多。终于解决了这个疑问。

封装的一个含义就是类的某个或几个数据是状态数据。他的改变只由行为(方法)来改变。并提供只读的查看。

服务端和客户端同步开发。

客户端的初始化行为放入main中(之后可以由网络模块发送消息,获得消息,并回调这些方法)。

客户端的动作逻辑封装成方法(之后由网络模块发送消息,获得消息,并回调这些方法)

服务端是一个完备的系统,应该是一个可以自检,自运行的系统。客户端只是通过发送消息,改变服务端的自运行的过程中的状态值。

c#

RoomInfo selectroom = rooms.Where(s => s.room_id == (SByte)this.comboBox1.SelectedValue).Single();

where 相当于里面一个bool函数。where里面已经回调了()里面的函数。并根据bool值来决定是否加入结果集合。

c++ get .set 生成器。

List<string> inputcode = new List<string>();
            List<string> outputcode = new List<string>();

            string className = this.textBox3.Text.Trim();

            inputcode = this.textBox1.Text.Split(new string[] {"
"}, StringSplitOptions.RemoveEmptyEntries).ToList();

            for(int i=0;i<inputcode.Count;++i)
            {
                
                string[] eachline=inputcode[i].Split(new string[] {" ",";"}, StringSplitOptions.RemoveEmptyEntries);

                if(eachline.Count()==2)
                {
                    string type=eachline[0];
                    string name=eachline[1];

                    this.textBox2.Text+=type+" "+className+"::Get"+name+"()"+System.Environment.NewLine;
                    this.textBox2.Text+="{"+System.Environment.NewLine;
                    this.textBox2.Text += "   " + "return " + name + ";" +System.Environment.NewLine;
                    this.textBox2.Text+="}"+System.Environment.NewLine;

                    this.textBox2.Text+="void "+className+"::Set"+name+"("+type+" _"+name+")"+System.Environment.NewLine;
                    this.textBox2.Text+="{"+System.Environment.NewLine;
                    this.textBox2.Text += "   " + name + "=_" + name + ";" + System.Environment.NewLine;
                    this.textBox2.Text+="}"+System.Environment.NewLine;

                    this.textBox2.Text=this.textBox2.Text.Replace("std::","");


                }

            }

目的:有时候有些情况比较复杂,写完了代码。也没法确定是否完全正确。画图感觉比较复杂,只能靠测试。这个时候使用状态机分析法。就能比较好。
步骤:先写出初始行为,和输入行为,以及输入行为对应的猜想的动作,通过猜想的动作,对状态的更改,判断状态是否合理,来验证行为是否正确。
每次集合中所有状态和行为一一匹配。有新状态。就保存。
之后每次用新状态和所有行为一一匹配。直到没有新状态为止。

初始状态: r_ok,s_ok,e_in;

输入行为和对应猜想动作()
1)recv_again. r_ok
2)recv_close. r_close,cancel event
3)recv_error. del
4)send_ok. s_ok ,1)close:yes,block:yes=>s_ok 2)close:yes,block:no => s_ok 3) colse:no,block:yes=>s_ok. e_in. 4)close:no,block:no=>s_ok
5)send_block. s_block,mod e_out
6)send_err. del


初始状态: 下和所有输入行为产生的新状态
1:r_ok,s_ok,e_in;

1-1)=>
1-2)=>r_close,s_ok
1-3)=>del
1-4)=>r_ok,s_ok,e_in
1-5)=>r_ok,s_block,e_out
1-6)=>del
状态应该正确。所以猜想行为暂时正确。
在用得到的新状态,和所有行为一一匹配
1:r_close,s_ok
2:r_ok,s_block,e_out

1-1)=>不可能会存在的行为
1-2)=>不可能会存在的行为
1-3)=>不可能会存在的行为
1-4)=>
1-5)=>r_close,s_block, e_out
1-6)=>del

2-1)=>不可能会存在的行为
2-2)=>不可能会存在的行为
2-3)=>不可能会存在的行为
2-4)=>
2-5)=>
2-6)=>del

又得到1种新状态。所有状态是2×2×2.现在只有4种。
在用得到的新状态,和所有行为一一匹配
1:r_close,s_block, e_out
1-1)=>不可能会存在的行为
1-2)=>不可能会存在的行为
1-3)=>不可能会存在的行为
1-4)=>
1-5)=>
1-6)=>del


无任何新状态。估算下是否正确
估算下,还有剩下4种是什么情况。
1:r_ok,s_ok,e_in;
2:r_ok,s_block,e_out
3:r_close,s_ok
4:r_close,s_block, e_out
哦。因为s_ 和e_只能组合成2种。
所以就是4种。
所以我们得到了全部状态。再验证一下猜想行为就好了。
虽然很烦琐,但是可以验证遗漏的情况。

测试epoll的时候,客户端可以线程10个内。但是开多点socket ,100左右。这样简陋的环境。也可以测试高流量,模拟高并发。注意看服务的发送和接受是否相同大小,如果是echo测试。

还要看客户端的接受。是否有重传现象。如果客户端接收的明显比服务端发送的多。

如何测试epoll的代码效率。

可以简单点。客户端开1000个socket.200毫毛休息一次。说明1秒有5000条信息处理。每条信息64B。发送速度就是300/kB.

服务端,每条信息的处理休息1毫秒。说明1秒处理1000条。但是测试还是不准。所以可以调整下。用netstat 命令查看。使得接受数据越来越多为好。说明程序处理慢。

这样就可以开始优化了。单线程可以优化批量发送,批量处理。

多线程就可以开始队列,新线程处理。多线程的一般特征是网路是没有问题的。接受快,发送快。因为单独线程再处理io。但是如果程序差,那么内存会原来越小。因为网络的数据全部拉到内存中去了。但是又处理不过来。

原文地址:https://www.cnblogs.com/lsfv/p/6042403.html