GCC 7和LLVM+Clang+libc++abi 4.0的构建脚本
之前的版本发完,有空来更新一下之前的gcc和llvm+clang工具链的编译脚本了。其实GCC 7是才release没多久但是llvm 4.0发布其实有一段时间了。
GCC
这回是GCC的脚本有一些改动。因为我现在开发机的环境很多组件并没有装,所以顺带发现了之前的构建脚本的一些问题。
之前的版本发完,有空来更新一下之前的gcc和llvm+clang工具链的编译脚本了。其实GCC 7是才release没多久但是llvm 4.0发布其实有一段时间了。
这回是GCC的脚本有一些改动。因为我现在开发机的环境很多组件并没有装,所以顺带发现了之前的构建脚本的一些问题。
在写这篇文章前,我突然想到以前流行了一段时间的服务器面试题:当一个BUG只有几百万分之一的概率会出现,怎么办?这个问题在这个BUG里只是毛毛雨而已,因为这次的BUG的出现概率是夸张的三亿分之一。
我在好几年前自己开发了一个用于服务器进程间通信的框架,libatbus,以前用在了客户端的模块隔离的通信心痛中。并且现在开始正式用于服务器。但是前两天看了一下服务器的日志,发现了比较奇怪的-202错误。
近期仍然在搭建完整的游戏服务器架构。基于atsf4g(asynchronously-tree server framework fo game)的完整解决方案终于接近完成。基本框架之前其实已经做完了,但是之前解决的只是基本的框架层代码,不包含任何特定的交互模型、协议模型、配置服务等等。这回就整理了一个只包含登入登出逻辑的完整工程,另外优化了一些小细节和周边工具的支持。
好久没写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。
但是每次停服更新的话用户体验是比较伤的,所以后来就采取了一些措施来减少更新的停服时间。最后基本实现了不停服更新。
atbus是我按之前的思路写得服务器消息通信中间件,目标是简化服务器通信的流程,能够自动选择最优路线,自动的断线重连和通信通道维护。能够跨平台并且高效。
近期优化底层库,完成atapp库的基本功能,顺带优化了一下atbus的一些功能,也是对高效的大幅优化。这次的优化起源于某一次的压力测试,先介绍下压力测试的结果吧。
这个问题起源于以前给客户端写的一个log模块,然后里面为了线程安全且多线程下不互相写乱,并且因为这些系统基本都用比较高版本的编译器,都支持C++11了,所以就用了C++11的TLS功能。
但是Android的默认std库并不是libstdc++或者libc++,而是Bionic。IOS不知道是什么版本的标准库都不支持thread_local的关键字。 这个之前写过一个记录提到过 Android NDK undefined reference to ___tls_get_addr 错误。如果使用这个关键字,链接的时候会报错说找不到符号。
之前写了个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版本的变化。
然而这次变化就比较大了,首先所有的API都变更了,汇编代码里的参数和返回值也都发生了变化,当然语义也不一样了,另外还增加了新的APIontop_fcontext。这些变化使得libcopp的逻辑关系也必须有一些相应的调整,为了理清思路,这些都在后面分析。
经过茫茫长时间的编写+过年在家无聊补充和修正单元测试,再加上这两天的整理,终于把以前的这个关于服务器通信中间件的基本功能和相应的单元测试完成啦。还是可以热烈庆祝一下的。
《关于BUS通信系统的一些思考(一)》 《关于BUS通信系统的一些思考(二)》 《关于BUS通信系统的一些思考(三)》
主要的思路还是在自动选择共享内存或是tcp或是unix socket进行通信。使用节点ID,屏蔽底层通信细节,屏蔽自动重连细节和节点之间自动建立直连的细节。同时基于目前的游戏服务器架构设计方式预留了一些拓展性的设计,以便于后续服务器框架的实现。主要是指全异步,树形结构,自动化的容灾设计和动态扩容缩容,不停服更新,统计等等。
记一下最近踩得两个C++独有的暗坑,其中一个和ABI相关。第二个坑其实之前研究过,但是没有实例,这次算是碰到了个典型的实例。
在项目中碰到的实例的大致流程是:
用代码表示的话,流程如下:
最近一个人搞后台,框架底层+逻辑功能茫茫多,扛得比较辛苦,一直没抽出空来写点东西。
空闲的时间,完善了LLVM+Clang+libc++和libc++abi的编译脚本。不得不说clang的编译脚本质量比gcc差不是一点点。为了在centos下尽可能编译出更多的功能和llvm的子项目,要各种改各种试才终于自举通过,并且这种情况编出来的二进制大得夸张。不过总算是告一段落。
因为项目需要,买了本《Redis的设计与实现》的电子版,顺便给这本书的作者贡献了一丢丢的Redis文档的翻译。这本书通篇贴代码,有点看blog的感觉,写得还是很简单易懂的。(不过谁告诉我为毛我花了30大洋买完不到半个月就变成10块了,坑爹么不是。T_T)
另外还零零散散地看了些《程序员的自我修养-链接、装载与库》 这本书云风之前推荐过。并且在我看得这些里国人写得书里,这确实是一本值得推荐,并且不可多得的佳作。
还是回到正题
早先我们用得都是tolua++,但是tolua++貌似很久没有更新了,而且不支持lua大于5.1的版本。并且在使用的过程中发现了一些坑,比较隐晦+恶心。总不能让所有人时时刻刻记住这些坑吧?再加上服务器的lua脚本会比较轻量级,索性就用一个简单高效的Lua绑定机制。
本来看到Android的ndk都开始用gcc4.8和gcc4.9了,而且gcc4.8.1开始支持全部的c++11的特性,我就很happy地用上了。结果出现这么个错误。
网上查到说是Android的run time竟然不支持 thread local storage(TLS),更准确地说,是它没实现。
LLVM和Clang工具链的生成配置文件写得比较搓,所以略微麻烦,另外这个脚本没有经过多环境测试,不保证在其他Linux发行版里正常使用。
如果第一次执行出现安装失败,可以再执行一次。llvm的安装脚本问题多多
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.pdf 和 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2555.pdf 虽然贴出来了。估计是没人看得。所以就直接说重点。
用过std和boost的function对象和bind函数的童鞋们都知道这玩意用起来腰不酸了,腿不疼了,心情也舒畅了。先上一个简单得示例:
std::string str;
std::function func = std::bind(&std::string::at, &str);
bool is_empty = func(); 但是这是怎么做到的呢?看完源码以后,你会发现这里面有着一些很巧妙的设计。
C++11的新标准已经出台,各个编译器已经开始陆续支持。 主流编译器支持程度见(VC++, gcc, clang, intel c++等):http://en.cppreference.com/w/cpp/compiler_support
但是要让C++11应用与生产环境还需时日,所以就在这里记录一下在过渡时期可能用到的一些重要功能
这是我对C++新特性系统学习的最后一部分,之后就靠实践中再来看新标准的新特性啦。
在之前,我对这部分没太在意,直到看到了一篇文章 [http://blog.csdn.net/pongba/article/details/1659952](http://blog.csdn.net/pongba/article/details/1659952) 才意识到,C++的多线程操作也是个麻烦的问题。
简而言之,C++编译器在进行编译优化的时候,认为当前是单进程的,并且遵循**可观察行为**(Observable Behavior)不变的原则。就是说在可观察行为不变的情况下,操作是可以被改变顺序的,而单进程可观察行为不变,不代表在多进程的情况下仍然不变。还是上大牛的例子:
_**例子一:**_
| x = y = 0; | |
| 线程1 | 线程2 |
| if(x == 1) ++y; | if(y == 1) ++x; |
完全可以优化成
C++在效率上有个硬伤。我们知道C#和Java对于类传递都是以引用的方式,而C++默认都是传值。在传值过程中就经常会进行复制构造,这完全没必要而且浪费CPU,为了解决这种问题,于是乎C++11 增加了一个新的非常数引用(reference)类型,称为右值引用(R-value reference)。我就专门看了一下关于右值引用的东西。 右值引用在GCC 4.3之后开始支持,VS 2010(VC 10.0)已经支持,再前一点的VC版本没试过所以不知道。 右值引用的申明标记为T &&,主要用于处理临时变量,比如函数返回的变量(暂时想不出其他例子,忽略返回值优化吧,(命名)返回值优化参见http://efnetcpp.org/wiki/Return_value_optimization,再说返回值优化能力有限是吧,比要求如单返回语句、不能使用异常等等),避免复制构造。同时在析构的时候就不会析构这个临时变量,从而提升效率。 上代码:
其实这个部分是我觉得最没用的部分
注:这部分仅测过GCC,VS暂不支持
在旧的标准C++中支持两种字符编码。
直接使用””将产生const char。
使用L””将产生const wchar。
新标准中增加了三种,即UTF-8、UTF-16和UTF-32。