好久没写blog了。最近空闲时间都在加紧完成atframework框架。总算是搞完了,并且搭建了一个静态介绍页。以后有空慢慢加文档进去。

主页: https://atframe.work/ Github: https://github.com/atframework/

目前这个项目已经是一个小型游戏服务器的完整框架,包括服务器间实例的管理、客户端和服务器的内部协议和通信机制。并且实现了纯C的port。 然后https://github.com/atframework/atsf4g-co/tree/master/sample/atgw_cli_inner_hello里提供了c++的客户度端的代码示例,https://github.com/atframework/AtgwInnerCli-CSharp里提供了C#的客户端代码示例。 使用的都是同一个纯C的协议porting。这样无论cocos还是unity框架接入都不困难了。其他的框架也可以直接用这个纯C的porting来接入。

我们目前的游戏第一次测试的时候笔记送匆忙,导致上线之后频繁更新。 比如BOSS战由于大区的人数和预期不一样导致的难度调整,或者是任务链或者数值调整,再加上一些BUG。

前言

之前写了个C++的协程框架libcopp,底层使用的是boost.context实现,然后剥离了对boost的依赖。然而这样意味着我必须时常跟进boost.context的更新。

顺带提一下这个协程库已经在我们线上服务器版本中使用了。

从最初的boost版本(我忘了从哪个版本开始了)一直到1.60版本,boost.context的变化都不大,都只是补全一些新的架构和体系结构,还有就是修复一些小细节的BUG,再就是增加了对valgrind的支持(之前写过一个Merge记录提到过)。新增的功能也只有execution_context(现在叫execution_context_v1),这个东西我的libcopp里其实包含了这个功能,并且本身做得比它要功能丰富,所以没有接入的必要。另外在1.60版本的时候尝试使用Windows里的fiber(当然默认是关闭的),在1.61版本里被移除了。这些细节都不是特别重要,主要还是1.61版本的变化。

libatbus

经过茫茫长时间的编写+过年在家无聊补充和修正单元测试,再加上这两天的整理,终于把以前的这个关于服务器通信中间件的基本功能和相应的单元测试完成啦。还是可以热烈庆祝一下的。

小记最近踩得两个C++坑

记一下最近踩得两个C++独有的暗坑,其中一个和ABI相关。第二个坑其实之前研究过,但是没有实例,这次算是碰到了个典型的实例。

坑一:常量引用失效

在项目中碰到的实例的大致流程是:

前言

本来想参考下tolua++的对象生命周期维护方式。一不小心发现了一个坑。

代码追踪

我这里用得是tolua++ 1.0.93版本。

tolua++在new一个类的时候,会把类指针作为userdata传入lua,建立metatable并通过tolua_classevents函数给metatable注册魔术方法。

LLVM和Clang工具链的生成配置文件写得比较搓,所以略微麻烦,另外这个脚本没有经过多环境测试,不保证在其他Linux发行版里正常使用。

如果第一次执行出现安装失败,可以再执行一次。llvm的安装脚本问题多多

INI 配置读取库发布

Github地址: https://github.com/owent/libiniloader

OSChina镜像: http://git.oschina.net/owent/libiniloader

项目中经常会碰到需要读取配置的情况,而用ini配置最大的优势就是简单易懂。 但是现在很多的配置读取库都过于庞大了,比如Boost.PropertyTree,功能很强大,但是基本不会用到里面所有的东西。 另外微软的INI读取,功能不是很强不说,还限制在Windows上,更重要的是API设计得实在不优雅。 于是libiniloader就诞生啦。

目录

C++ 的Lambda表达式

C++ 11 标准发布,各大编译器都开始支持里面的各种新特性,其中一项比较有意思的就是lambda表达式。

语法规则

C++ 11 Lambda表达式的四种声明方式

C++11标准里有动态模板参数已经是众所周知的事儿了。但是当时还有个主流编译器还不支持。 但是现在,主要的编译器。VC(Windows),GCC(Windows,Linux),Clang(Mac,IOS)都已经支持了。所以就可以准备用于生产环境了。 type_traits没啥好说的。主要是一些静态检测。主要还是要看动态模板参数和他们两的结合使用上。 动态模版参数标准文档见: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2242.pdfhttp://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2555.pdf 虽然贴出来了。估计是没人看得。所以就直接说重点。

前几天我们项目的日志系统出现了一点问题,但是一直没有时间去深究。 昨天在同事的帮助下,无意中猜了一种可能性,结果还真被我猜中了,于是今天就特别研究了一下,记录下来。

接上一篇 VC和GCC内成员函数指针实现的研究(二)

虚继承

终于到最后的虚继承了。

测试代码如下:

#include <ctime>
#include <vector>
#include <algorithm>
#include <cstdio>
#include <stdint.h>
#include <cstddef>
#include <string>

class foo_a
{
public:
    virtual ~foo_a(){}
    virtual void info() {
        printf("%s:%d\n", __FUNCTION__, __LINE__);
    }

    void print(){
        printf("%s:%d\n", __FUNCTION__, __LINE__);
    }
};

class foo_l
{
public:
    int l;
    foo_l(): l(1){}

    virtual void info() {
        printf("%s:%d\n", __FUNCTION__, __LINE__);
    }
};

class foo_r: virtual public foo_a
{
public:
    int r;
    foo_r(): r(2){}
};

class foo_c: virtual public foo_l, public foo_r
{
public:
    virtual void info() {
        printf("%d,%d. %s:%d\n", l, r, __FUNCTION__, __LINE__);
    }
};


int main(int argc, char* argv[]) {
    void (foo_a::*vptr1)() = &foo_a::info;
    void (foo_l::*vptr2)() = &foo_l::info;
    void (foo_a::*ptr)() = &foo_a::print;

    foo_c c;
    foo_r r;
    foo_a a;

    printf("pword size = %d\n", (int)(sizeof(size_t)));
    printf("address of &foo_a::info = 0x%llxH\n", &foo_a::info);
    printf("pointer to &foo_a::info = 0x%llxH\n", vptr1);
    printf("sizeof vptr = %d\n", (int)(sizeof(vptr1)));

    (a.*vptr1)();
    (r.*vptr1)();
    (c.*vptr1)();
    (c.*vptr2)();
    c.info();

    (c.*ptr)();

    return 0;
}

VC虚继承成员函数指针实现

因为是兼容虚继承和非虚继承的,所以赋值的部分的汇编是一样的。这里就不贴了。关键在于执行期它是怎么找到虚基类的。请往下看:

接上一篇 VC和GCC内成员函数指针实现的研究(一)

接下来是多重继承,用到的测试代码如下所示:

#include <ctime>
#include <vector>
#include <algorithm>
#include <cstdio>
#include <stdint.h>
#include <cstddef>
#include <string>

class foo_a
{
public:
    virtual ~foo_a(){}
    virtual void info() {
        printf("%s:%d\n", __FUNCTION__, __LINE__);
    }
};

class foo_b
{
public:
    virtual ~foo_b(){}

    // 这个函数用于试foo_b的结构与foo_a不同
    // 以防止VC对foo_a和foo_b的`vcall'{8}'的代码合并
    virtual void inspect() { 
        printf("%s:%d\n", __FUNCTION__, __LINE__);
    } 

    virtual void info() {
        printf("%s:%d\n", __FUNCTION__, __LINE__);
    }

    void print() {
        printf("%s:%d\n", __FUNCTION__, __LINE__);
    }
};


class foo_c: public foo_a, public foo_b
{
public:
    virtual void info() {
        printf("%s:%d\n", __FUNCTION__, __LINE__);
    }
};


int main(int argc, char* argv[]) {
    void (foo_a::*vptr1)() = &foo_a::info;
    void (foo_b::*vptr2)() = &foo_b::info;
    void (foo_b::*ptr)() = &foo_b::print;

    foo_c c;
    foo_b b;
    foo_a a;

    
    printf("word size = %d\n", (int)(sizeof(size_t)));
    printf("address of &foo_a::info = 0x%llxH\n", &foo_a::info);
    printf("pointer to &foo_a::info = 0x%llxH\n", vptr1);
    printf("address of &foo_b::info = 0x%llxH\n", &foo_b::info);
    printf("pointer to &foo_b::info = 0x%llxH\n", vptr2);
    printf("sizeof vptr = %d\n", (int)(sizeof(vptr1)));

    (a.*vptr1)();
    (b.*vptr2)();
    (c.*vptr1)();
    (c.*vptr2)();

    (c.*ptr)();

    return 0;
}

VC多重继承成员函数指针实现

最近在《C++对象模型》一书里说到的virtual的成员函数指针,低于128的被cfront编译器认为是虚表偏移量(支持子类对父类函数的覆盖)。VC只是提了下单继承、多继承和虚继承的实现方案不同,GCC没有提及,所以就专门稍微深入分析研究下他们的实现机制。

Linux 常用工具

  • enca: http://dl.cihar.com/enca/   文件名编码转换
  • iconv: 文件编码转换
  • convmv: 文件名编码转换
  • ldd: 查看可执行文件或动态链接库的依赖库
  • getconf: 查看配置信息(如getconf LONG_BIT可知当前系统是32位还是64位版本)
  • tcpdump: 监视网络服务
  • sync: 将缓冲区内容写入磁盘
  • echo 3 > /proc/sys/vm/drop_caches: 手动释放缓存
  • nm: 查看符号表
  • readelf: 查看ELF信息(Executable and Linkable Format)
  • man: 文档
  • top/htop: 查看最高占用
  • perf: 性能数据采集
  • sar: 系统信息采集
  • uptime: 系统1分钟、5分钟和15分钟的系统平均负载
  • free: 内存使用情况
  • iostat: 磁盘IO使用情况
  • pidstat: 查看进程状态
  • ipcs: 查看共享内存、消息、信号量信息,如:ipcs -m 共享内存
  • objdump –CS –l [bin文件]: 不反人类的反编译
  • strace: 系统调用跟踪
  • pstack: 查看当前调用栈
  • lsof: 查看打开的文件
  • ip addr: 查看ip地址

man [章节号] 手册名称: