一.Think库
提供跨平台的C语言库,各类C、C++程序都可以用到其中的东西,已支持AIX、HP-UX、Solaris、FreeBSD、Linux、Mac OS X和Windows操作系统
 
本人辛苦了四年,颠覆多次,终成这个发布版,现在作为unix-center的开源项目,任何非册用户进入此链接都可以下载  
有兴趣的先顶一下,便于后面的伙计看到此贴。  
第二版主要增加了进程通讯的一些东西,包括线程,线程锁,进程锁,信号量,共享内存及由信号量与共享内存实现的消息队列 
下载地址: 
http://unix-center.org/projects/think/
以下为网站公布的部分接口文档: 
发表人: enigma1983 Unix-Center 
日期: 2009-08-22 21:15 
概要: Think库之NET接口(socket接口) 
项目: Think  
Think NET是socket通讯的基本操作的封装,提供connect、listen、accept、send、recv、close几个基本接口,另外对select进行了封装,对包含socket名柄信息的双向循环链表进行侦听,同样也对UNIX上的poll实现了同样的封装,喜欢用poll的只需更换函数名即可,其它操作完全一样 
struct __think_net { 
int sockfd; 
char ip[16]; 
unsigned short port; 
int flags; 
}; 
typedef struct __think_net THINK_NET; 
1:建立连接 
THINK_NET *think_netconnect(const char *ip,unsigned short port); 
参数故名思意 
2:建立侦听 
THINK_NET *think_netlisten(const char *ip,unsigned short port); 
3:THINK_NET *think_netaccept(THINK_NET *net); 
net为侦听名柄 
4:接收数据 
int think_netrecv(THINK_NET *net,void *buf,unsigned int siz,int flags); 
buf为数据存放地址 
siz为大小 
flags为标志,可以接受的值为THINK_NET_WAIT,即一直等到siz个字节全部接收完毕或有错误时才返回 
5:发送数据 
int think_netsend(THINK_NET *net,const void *buf,unsigned int len,int flags); 
flags意思与think_netrecv中的相同,此处为len个字节全部发送完毕 
6:关闭连接 
int think_netclose(THINK_NET *net); 
7:加载动态库(Windows平台必须要调用的) 
int think_netstart(void); 
int think_netstop(void); 
netstart为使用网络接之间要调用的,netstop为不使用网络时候调用,也可以由程序退出时自动执行,即think_netstart是必须要执行的。 
struct __think_netlist { 
THINK_NET *net; 
int flags; 
struct __think_netlist *prior; 
struct __think_netlist *next; 
}; 
typedef struct __think_netlist THINK_NETLIST; 
8:向链表中增加一个连接 
int think_netlist_add(THINK_NETLIST **netlist,THINK_NET *net); 
netlist为链表的地址,如定义一个变量THINK_NETLIST *netlist=NULL,调用时传&netlist即可 
9:从链表删除一个连接 
int think_netlist_del(THINK_NETLIST **netlist,THINK_NET *net); 
10:在链表中查找一个连接 
THINK_NETLIST *think_netlist_find(THINK_NETLIST *netlist,THINK_NET *net); 
11:清理链表 
int think_netlist_clean(THINK_NETLIST **netlist); 
调用think_netlist_del时,只是将标志位置为已删除,并未真正从链中删除,因此需要调用这个接口进行清理 
12:释放链表 
int think_netlist_free(THINK_NETLIST **netlist); 
将删除所有连接,并释放内存 
13:使用select进行侦听 
int think_netselect(THINK_NETLIST **netlist,int timeout); 
timeout为等待时间 
>0为阻塞式等待一定时间,直到超时 
=0为非阻塞式,立即返回 
<0为永久阻塞式,直到有事件发生 
THINK_NETLIST结构中有一个成员flags,要在调用think_netselect之前,将需要侦听的事件设置好,如将flags设为THINK_NET_READ或THINK_NET_WRITE或THINK_NET_READ|THINK_NET_WRITE,即侦听读、写、读写 
think_netselect返回后,通过检查该标志是否被置位成THINK_NET_READ、THINK_NET_WRITE,以得知连接目前为可读或可写 
14:使用poll进行侦听 
int think_netpoll(THINK_NETLIST **netlist,int timeout); 
用法与think_netselect完全一样 
15:发送消息 
int think_netsendmsg(THINK_NET *net,const void *buf,unsigned int len); 
将先送四字节网络字节序的长度,然后再发送具体长度的信息 
16:int think_netrecvmsg(THINK_NET *net,void *buf,unsigned int siz); 
先接收四字节网络字节序的长度,然后再接收具体长度的信息 
发表人: enigma1983 Unix-Center 
日期: 2009-08-22 21:54 
概要: Think库之NETCENTER接口(socket通讯框架) 
项目: Think  
Think NETCENTER是借鉴ACE的设计思路,即使用select对所有连接进行侦听,如有连接上有事件发生,则调用相应的回调函数进行处理,这里采用缓冲的方式先将数据接收到缓冲区,然后调用相应的回调函数进行处理,当然如果接口是可写的,那么将查看写缓冲区是否有数据,如果有则从缓冲区读取数据进行发送。 
1:建立网络中心 
THINK_NETCENTER *think_netcenter_new(); 
主要是得到一个名柄,网络中心操作名柄 
2:进行一次网络处理 
int think_netcenter_idle(THINK_NETCENTER *netcenter,int timeout); 
这个接口为网络中心的总控接口,它先去调用select进行事件侦听,然后进行数据接收并调用回调函数进行处或从缓冲区发送数据,直到所有接口处理完毕后才返回,应用层需要不断调用此接口完成网络数据的持续处理 
timeout与think_netselect中的意思完全一样,这个参数就是原封不动的传给think_netselect的。 
3:释放网络中心 
int think_netcenter_free(THINK_NETCENTER *netcenter); 
这个接口将释放所有表及内存 
4:向网络中心注册连接 
THINK_NETCENTER_NETLIST *think_netcenter_netadd(THINK_NETCENTER *netcenter,THINK_NET *net,THINK_NETCENTER_NETHANDLE nethandle); 
net为所要注册的连接 
nethandle为该连接的回调函数地址 
5:从网络中心注销连接 
int think_netcenter_netdel(THINK_NETCENTER *netcenter,THINK_NET *net); 
6:从网络中心查找连接 
THINK_NETCENTER_NETLIST *think_netcenter_netfind(THINK_NETCENTER *netcenter,THINK_NET *net); 
7:清理网络中心的链表 
int think_netcenter_netclean(THINK_NETCENTER *netcenter); 
与think_netclean的意思一样,删除时只是置了标志,因此需要进行清理 
8:从连接缓冲中读取数据 
int think_netcenter_recv(THINK_NETCENTER_NET *net,void *buf,unsigned int siz); 
该函数是在回调中调用的,当有数据可读时,通过这个接口可获取数据 
9:向连接缓冲区中写入数据 
int think_netcenter_send(THINK_NETCENTER_NET *net,const void *buf,unsigned int len); 
该函数是在业务处理时调用的,当需要发送数据时,通过这个接口将数据发送到该连接的缓冲区中,由网络中心在idle时进行发送 
10:从缓冲区中窃取数据 
int think_netcenter_peek(THINK_NETCENTER_NET *net,void *buf,unsigned int siz); 
当不知道缓冲区里有什么数据时,可用此接口进行偷窥,即将数据取出来,但缓冲区的数据仍原封不动的保留在那里,这个接口在判断缓冲区是否有完整的数据包时很有用 
以下为使用GL语言通讯时使用的接口 
11:判断缓冲区是否有完整的数据包 
int think_netcenter_ismsgok(THINK_NETCENTER_NET *net); 
完整的数据包即四字节网络字节序的长度+对应的数据内容都在缓冲里了 
12:从缓冲区接收一个数据包 
int think_netcenter_recvmsg(THINK_NETCENTER_NET *net,void *buf,unsigned int siz); 
13:向缓冲区发送一个数据包 
int think_netcenter_sendmsg(THINK_NETCENTER_NET *net,const void *buf,unsigned int len); 
以下为网络中心内部使用的接口 
14:从网络上接收数据至缓冲区中 
int think_netcenter_recvto(THINK_NETCENTER_NET *net); 
15:从缓冲区中读取数据发送到网络上 
int think_netcenter_sendfrom(THINK_NETCENTER_NET *net); 
16:对网络中心的连接进行侦听 
int think_netcenter_select(THINK_NETCENTER *netcenter,int timeout); 
即对每个连接置相应的侦听标志,然后调用think_netselect进行侦听
  昨天一个同事一大早在群里推荐了一个google project上的开源内存分配器(http://code.google.com/p/google-perftools/),据说google的很多产品都用到了这个内存分配库,而且经他测试,我们的游戏客户端集成了这个最新内存分配器后,FPS足足提高了将近10帧左右,这可是个了不起的提升,要知道3D组的兄弟忙了几周也没见这么大的性能提升。
如果我们自己本身用的crt提供的内存分配器,这个提升也算不得什么。问题是我们内部系统是有一个小内存管理器的,一般来说小内存分配的算法都大同小异,现成的实现也很多,比如linux内核的slab、SGI STL的分配器、ogre自带的内存分配器,我们自己的内存分配器也和前面列举的实现差不多。让我们来看看这个项目有什么特别的吧。
一、使用方法
 
打开主页,由于公司网络禁止SVN从外部更新,所以只能下载了打包的源代码。解压后,看到有个doc目录,进去,打开使用文档,发现使用方法极为简单:
To use TCMalloc, just link TCMalloc into your application via the "-ltcmalloc" linker flag.再看算法,也没什么特别的,还是和slab以及SGI STL分配器类似的算法。
unix环境居然只要链接这个tcmalloc库就可以了!,太方便了,不过我手头没有linux环境,文档上也没提到windows环境怎么使用,
打开源代码包,有个vs2003解决方案,打开,随便挑选一个测试项目,查看项目属性,发现仅仅有2点不同:
1、链接器命令行里多了
  "..\..\release\libtcmalloc_minimal.lib",就是链接的时候依赖了这个内存优化库。
2、链接器->输入->强制符号引用 多了 __tcmalloc。
这样就可以正确的使用tcmalloc库了,测试了下,测试项目运行OK!
 
 
二、如何替换CRT的malloc
 
从前面的描述可知,项目强制引用了__tcmalloc, 搜索了测试代码,没发现用到_tcmalloc相关的函数和变量,这个选项应该是为了防止dll被优化掉(因为代码里没有什么地方用到这个dll的符号)。 
初看起来,链接这个库后,不会影响任何现有代码:我们没有引用这个Lib库的头文件,也没有使用过这个dll的导出函数。那么这个dll是怎么优化应用程序性能的呢? 
实际调试,果然发现问题了,看看如下代码 
    void* pData = malloc(100); 
00401085 6A 64            push        64h   
00401087 FF 15 A4 20 40 00 call        dword ptr [__imp__malloc (4020A4h)]  
跟踪 call malloc这句,step进去,发现是 
78134D09 E9 D2 37 ED 97   jmp         `anonymous namespace'::LibcInfoWithPatchFunctions<8>::Perftools_malloc (100084E0h)  
果然,从这里开始,就跳转到libtcmalloc提供的Perftools_malloc了。 
原来是通过API挂钩来实现无缝替换系统自带的malloc等crt函数的,而且还是通过大家公认的不推荐的改写函数入口指令来实现的,一般只有在游戏外挂和金山词霸之类的软件才会用到这样的挂钩技术, 
而且金山词霸经常需要更新补丁解决不同系统兼容问题。 
三、性能差别原因
 
如前面所述,tcmalloc确实用了很hacker的办法来实现无缝的替换系统自带的内存分配函数(本人在使用这类技术通常是用来干坏事的。。。),但是这也不足以解释为什么它的效率比我们自己的好那么多。 
回到tcmalloc 的手册,tcmalloc除了使用常规的小内存管理外,对多线程环境做了特殊处理,这和我原来见到的内存分配器大有不同,一般的内存分配器作者都会偷懒,把多线程问题扔给使用者,大多是加 
个bool型的模板参数来表示是否是多线程环境,还美其名曰:可定制,末了还得吹嘘下模板的优越性。 
tcmalloc是怎么做的呢? 答案是每线程一个ThreadCache,大部分操作系统都会支持thread local storage 就是传说中的TLS,这样就可以实现每线程一个分配器了, 
这样,不同线程分配都是在各自的threadCache里分配的。我们的项目的分配器由于是多线程环境的,所以不管三七二十一,全都加锁了,性能自然就低了。 
仅仅是如此,还是不足以将tcmalloc和ptmalloc2分个高下,后者也是每个线程都有threadCache的。 
关于这个问题,doc里有一段说明,原文贴出来: 
ptmalloc2 also reduces lock contention by using per-thread arenas but there is a big problem with ptmalloc2's use of per-thread arenas. In ptmalloc2 memory can never move from one arena to another. This can lead to huge amounts of wasted space. 
大意是这样的:ptmalloc2 也是通过tls来降低线程锁,但是ptmalloc2各个线程的内存是独立的,也就是说,第一个线程申请的内存,释放的时候还是必须放到第一个线程池中(不可移动),这样可能导致大量内存浪费。 
  
四、代码细节
1、无缝替换malloc等crt和系统分配函数。
 
   前面提到tcmalloc会无缝的替换掉原有dll中的malloc,这就意味着使用tcmalloc的项目必须是 MD(多线程dll)或者MDd(多线程dll调试)。tcmalloc的dll定义了一个 
static TCMallocGuard module_enter_exit_hook; 
的静态变量,这个变量会在dll加载的时候先于DllMain运行,在这个类的构造函数,会运行PatchWindowsFunctions来挂钩所有dll的 malloc、free、new等分配函数,这样就达到了替换功能,除此之外, 
为了保证系统兼容性,挂钩API的时候还实现了智能分析指令,否则写入第一条Jmp指令的时候可能会破环后续指令的完整性。 
2、LibcInfoWithPatchFunctions 和ThreadCache。
 
LibcInfoWithPatchFunctions模板类包含tcmalloc实现的优化后的malloc等一系列函数。LibcInfoWithPatchFunctions的模板参数在我看来没什么用处,tcmalloc默认可以挂钩 
最多10个带有malloc导出函数的库(我想肯定是够用了)。ThreadCache在每个线程都会有一个TLS对象: 
__thread ThreadCache* ThreadCache::threadlocal_heap_。 
3、可能的问题
 
设想下这样一个情景:假如有一个dll 在tcmalloc之前加载,并且在分配了内存(使用crt提供的malloc),那么在加载tcmalloc后,tcmalloc会替换所有的free函数,然后,在某个时刻, 
在前面的那个dll代码中释放该内存,这岂不是很危险。实际测试发现没有任何问题,关键在这里: 
 span = Static::pageheap()->GetDescriptor(p); 
    if (!span) { 
      // span can be NULL because the pointer passed in is invalid 
      // (not something returned by malloc or friends), or because the 
      // pointer was allocated with some other allocator besides 
      // tcmalloc.  The latter can happen if tcmalloc is linked in via 
      // a dynamic library, but is not listed last on the link line. 
      // In that case, libraries after it on the link line will 
      // allocate with libc malloc, but free with tcmalloc's free. 
      (*invalid_free_fn)(ptr);  // Decide how to handle the bad free request 
      return; 
    }  
tcmalloc会通过span识别这个内存是否自己分配的,如果不是,tcmalloc会调用该dll原始对应函数(这个很重要)释放。这样就解决了这个棘手的问题。 
五、其他
 
其实tcmalloc使用的每个技术点我从前都用过,但是我从来没想过用API挂钩来实现这样一个有趣的内存优化库(即使想过,也是一闪而过就否定了)。 
从tcmalloc得到灵感,结合常用的外挂技术,可以很轻松的开发一个独立工具:这个工具可以挂载到指定进程进行内存优化,在我看来,这可能可以作为一个外挂辅助工具来优化那些 
内存优化做的很差导致帧速很低的国产游戏。 
小内存分配器主要作用是“减小内存碎片化趋势,减小薄记内存比例,提高小内存利用率”,从性能上说,系统内存分配器已针对小内存分配进行优化,单纯使用自定义的小内存分配器,对性能帮助不会很大。内置分配器意义还是体现在,实现无锁分配,避免API调用切换开销。 
CRT自身new-delete会用到500个时钟周期,而一个CS会消耗50个时钟周期,一个mutex会用到2000个时钟周期,以上是无竞争的情况。所以,如果用mutex做互斥,那还不如用系统的分配器;如果用CS,也不见会好多少,因为CS会随锁竞争加剧大幅增加时间,甚至会超过mutex。 
所以结论是,对于单线程,内置分配器有一定的价值;对于多线程,带锁内置分配器基本上可以无视了(至少对于winxp以后是这样,win2k好像要打补丁)呵呵,从你说的情况来看,很有可能你们原来的分配器用mutex帮倒忙了。 
tcmalloc中的唯一亮点应该是,如何做到跨线程归还内存,又能保持高性能,猜想可能使用了某种二级分配策略,内存块可以属于任何线程的内存池,归还到那个线程内存池,就由这个内存池管理。由于各个线程的分配和释放多半不平衡,有线程池会撑满,有的会不足。估计撑满的就会归还到公共内存池。第一级分配无锁,如果内存池不足了,就进入第二级带锁批量分配,而且第二级分配会先从公共内存池获取,如果还不够,这才使用系统内存分配,这该算是第三级分配了。 最后,tcmalloc也是可以用于MT版本的哦,详见才能看见)http://groups.google.com/group/google-perftools/browse_thread/thread/41cd3710af85e57b
三、跨平台的USB设备访问C语言库,libusb
libusb的是一个C库,它提供通用的访问USB设备。它支持Linux,Mac OS X,Windows,Windows CE,Android,和OpenBSD/ NetBSD。

版本说明:此版本标志着将libusbx项目合并成libusb。
 
 
 
四、可直接商用的跨平台c,c++动态线程池,任务池stpool库
 
  stpool是一个轻便高效的动态跨平台的线程池/任务池库. 
     
     常规线程池的缺点:
           1. 总是启动时候就开启固定数目的线程,而不管系统的繁忙状态     
                    (这是很浪费系统资源的).
           2. 当任务繁重的时候,即使线程池被设计成可继续添加更多线程来服务
            ,由于实时服务状态暴漏给  用户的太少,所以线程添加数目会给用户会
             带来额外的编程麻烦, 而且性能不怎么好
                    (对应用的扩展性太差,同时外在人工干预性太强)
     如果你在寻找一个具有如下特性的线程池库:
         1.  系统空闲时候线程能自动退出.任务到来时候自动启动线程服务
         2.  线程池自动根据任务执行时间和数量智能启动合适的线程数目来服务.达到最好的调度性能
         3.  能随时调整和控制线程池中服务线程上下限
         4.  跨平台,同时支持 c, c++
     那么stpool满足你的要求.   
      
           (你只管提交你的任务,其他所有你关心的,需要的特性, 以及你认为的瓶颈stpool替你解决)
         
       线程池的难点在于: 
          1.怎样动态创建线程执行任务,因为任务运行时间不一,即使同一类型的任务,因为逻辑的
      触发条件不一致,可能导致执行时间千差万别, 更别说各种类型不一致的任务同时投递到一个线程池中。
          2. 对于大量任务投递进来时候,到底该创建多少线程来服务? 仅仅根据任务数量开启对应的
      线程数是肯定不行的.
  
         本线程池解决了这些难点,而且跨平台.线程池动态创建线程,动态销毁, 在系统空闲时候,
   耗费系统资源极小.基本为0,同时在某个时间点大量并发任务产生时候,又能快速跟进提供固定线程
   始终不退出的线程池的优点,同时会根据任务状态和多少智能创建线程调度任务.
  . 库内容
      stpool.h  (头文件,组件API集合描述)
      ===================================
     已经支持的平台: Windows, Linux, ARM, Android, MAC/IOS
     ===================================
WIN32             LINUX         其它支持   libstpool.lib      libstpool.a   
   libstpool.dll      libstpool.so
特性:
     1. 采用c语言编写,提供丰富的API接口. (已c++接口支持)
   
     2. 对os层进行了抽象,使具有良好的跨平台的能力(支持win32,linux,unix,arm)
   
     3. 轻便快速, API接口自然易于使用,可直接商用,支持32位,64位系统
   
     4. 能随时调整和控制线程池的线程数目, 内部已智能动态维护力求使其占用
         最小的系统资源来最快速调度任务
.    5. 支持优先级任务,同时内置内存对象池,减少运行时间长带来的内存碎片
     6.  线程池能同时支持任意类型的任务, 一个线程池中如果加入延时的,和非延时的,
         以及延时到一定程度的等各种不同类型的任务,stpool都能完美的工作.能选择最合适
         的线程数目来提供服务  (可自行编写demo连接debug库进行实时监控验证)
应用场景:
        适合间歇性或者持续性的并发程度高,任务执行时间较短的应用系统. 
   
     比如下面一些常用的应用场景.
           1.高并发服务器,利用线程池来提高响应度
           2.在没有asio的系统上利用线程池实现asio是对用户大量回调的反馈
           3.对应用数据的预处理,比如web服务用户接入时需要用户验证等都可以作为
              预处理等放入线程池处理,完成后再放入统一的事件调度器中(如libevent)
             ,提高web高并发访问.
           4.并行计算, 如在多核CPU上进行数据并行帧数据编解码.
           5.网络爬虫或者文件并行搜索,下载等
           6.临时多任务处理加速.(比如: 程序启动时按任务进行服务加速,多视频通道打开加速)
============================================================
libstpool高级特性:
         libstpool 3.0 现已支持group组控制. (库已开放), 整个app都可以设计运行在libstpool库上. 可以
严格精细控制app线程环境.
 能满足需求:
        1.对任务进行分组,可以独立对组控制,支持所有常见访问控制
 
gid = stpool_group_create(pool, "my_group", 1, 0); //创建组
         stpool_task_set_gid(ptsk, gid);            //设置任务组ID
         stpool_group_set_attrl(pool, gid, attr); //设置组调度属性 (任务并发数限制)
         stpool_group_suspend(pool, gid, 0);    //暂停所有组任务调度
         stpool_group_resume(pool, gid);         //恢复对组的调度
         stpool_group_remove_all(pool, gid);    //移除组上所有任务
         stpool_group_wait_all(pool, gid, ms);    //等待组上所有任务完成
         stpool_group_wait_cb(poo, gid, wcb, wcb_args, ms);  //访问组上任务,由wcb回调决定是否等待该任务
         stpool_group_wait_any(pool, gid, ms);   //等待组上任一任务完成
         stpool_group_mark_all(pool, gid, lflags); //对组上所有任务做lflags标记
         stpool_group_mark_cb(pool, gid, wcb, wcb_args);  //定制化对组上任务标记
         stpool_group_delete(pool, gid);       //删除组
 场景1:
        一个app有10个比较耗时的任务(比如加速10个通道视频的掉线重连需求,SDK被设计成只能支
持串行),其它有2个并发线程负责log,   3个并发线程负责网络IO请求, ......, 各种各样的需求,每种需求
都需要线程服务. 必须对其单独开启线程并发.  有的线程因为不忙而被创建空等待, 能否将所有需求全部
配置到一个任务池中进行共享?
   共享会带来的问题是,有的需求任务过多会消耗过多线程而导致饥饿其它突发性的需要及时响应的需求
  libstpool的组服务完全可以满足如上所以需求:
       1. libstpool的task的优先级能保证突发性的响应需求得到及时调度
       2. libstpool的group组就像一个沙箱一样可以配置属性严格限制其在该组上并发的任务数而解
          决饥饿问题
       3. libstpool里的线程可以供所有group共享, 达到很好的系统性能(当libstpool在满足所有的
          group配置需求 后,还有冗余的时候,其会从所有group中选中一些任务来执行,提供了响应 
         ,这对group来说, 它只配置了并发性为n的任务,但因为共享的好处,它获得了n + k的优惠),
         当其它有新活动组加入时,其并发线程数会迅速的限制在limit_parralle_tasks内
     libstpool3.0 库 (linux&win 32/64位)下载:
             
     
     libstpool3.2 重构框架,支持静态线程池,动态线程池,任务组,框架对特定需求的性能优化具有良好的扩展性和伸缩性 
  
 
 
标签:
 
 
代码片段(10)[全屏查看所有代码]
 
  
1. [文件] libstpool-3.2.rar ~ 4MB 下载(87)
 
  
2. [文件] libstpool.2.6.6库+文档+demo.rar ~ 2MB 下载(126)
 
  
3. [代码]stpool 线程池,任务池
 
   
 
     
|  | 
 
  
4. [文件] demo-c++.cpp ~ 3KB 下载(12)
 
   
 
     
|  | 
 
  
5. [图片] linux_win_demo-c++.png
 
   

 
  
6. [文件] demo-sche.c ~ 3KB 下载(8)
 
   
 
     
|  | 
 
  
7. [图片] win32_linux_demo_sche1.jpg
 
   

 
  
8. [图片] win32_linux_demo_sche2.jpg
 
   

 
  
9. [代码]demo-sche结果分析
 
   
 
     
|  | 
 
  
10. [文件] demo.c ~ 7KB 下载(9)
 
   
 
     
|  | 
 
五、一个轻量级跨平台c开发库:TBOX 
 
| 简介  TBOX是一个用c语言实现的多平台开发库,支持windows、linux、mac、ios、android以及其他嵌入式系统。 针对各个平台,封装了统一的接口,简化了各类开发过程中常用操作,使你在开发过程中,更加关注实际应用的开发,而不是把时间浪费在琐碎的接口兼容性上面,并且充分利用了各个平**有的一些特性进行优化。 流库  针对http、file、socket、data等流数据,实现统一接口进行读写,并且支持: 阻塞、非阻塞、异步 三种读写模式。 支持中间增加多层filter流进行流过滤,实现边读取,内部边进行解压、编码转换、加密等操作,极大的减少了内存使用。 主要提供以下特性: 
 asio库  
 数据库  
 xml库  
 内存库  
 容器库  
 算法库  
 网络库  
 数**算库  
 libc库  
 libm库  
 object库  
 平台库  
 压缩库  
 字符编码库  
 实用工具库  
 | 
六、一款高效、灵活、跨平台的内存池
项目地址:https://code.google.com/p/elr-memery-pool/
简介
这是一款高效、灵活、跨平台的内存池实现。使用MIT Licence发布,完全不排斥商业使用。它已经在许多生产环境中使用了。在该实现中内存被划分为节点(node)和切片(slice)。node一大块内存,slice是node上的小片内存,从内存池中申请的每一个内存都属于一个slice。每一个内存池实例里德slice都是一样大小的,所以这个内存池更像对象池。但是仍然可以基于该内存池实现一款更加灵活的可以从中申请不同尺寸的内存的内存池。
node链接成一个链表,可以使用的slice也链接成一个链表。当从内存池中申请内存时,首先检查是否有空闲的slice,如果有取出一个;如果没有,就检查最近申请的node里是否还有从未使用过的切片。如果最近申请的node里有从未使用过的slice,那么取出一个;如果没有将这个node添加到node链表的头部再申请一个新node并从中取出一个slice返回。释放内存时,仅仅需要将slice插入到空闲的slice链表头部。
这个内存池被组织为树状结构。当创建一个内存池时,可以为其指定父内存池,在调用elr_mpl_create时使用父内存池的指针作为第一个参数即可。当一个内存池被销毁时,它的子内存池也会被销毁。所以当一个内存池和它的子内存池不再使用时不必将所有的内存池一一销毁,仅仅为父内存池调用销毁接口即可。如果在创建内存池时不指定父内存池,那么一个全局的内存池就是它的父内存池。它是在第一次调用初始化内存池函数(elr_mpl_init)时被创建的。所有的内存池结构所占据的内存空间都来自于这个全局内存池。在最后一次调用终止化(elr_mpl_finalize)内存池时这个全局内存池被销毁。同时可以看出所有的内存池实例都是这个全局内存池的直接或者间接的子内存池。那么当elr_mpl_finalize被调用后所有的内存池实例也将被销毁。这将内存泄露的可能性降到了最低。
这个内存池也支持多线程。如果需要在多线程环境下使用它,就需要实现elr_mtx.h中定义的六个接口并且在编译时定义宏ELR_USE_THREAD。幸运的是实现它们非常简单,并且已经提供了一个windows平台下的实现。在提供windows平台下的实现时也考虑到了linux的兼容性。所以原子计数器类型和计数器类型(counter(interger) type and counter value type )被分别定义了。在windows平台下并没有对原子计数器类型单独定义,而是提供一个被volatile修饰的LONG类型。在LONG和volatile LONG之间赋值是被允许的。在linux平台下原子计数器类型被定义为这样:typedef struct { volatile int counter; } atomic_t; 。在int和atomic_t之间赋值是违法语法的。
这个内存池在生产环境中被证明是非常有效的。即使如此这个内存池也有很大的改良空间。在多线程环境下使用时,每一个内存池实例都拥有一个互斥体,很多情形下这不是必须的。所以这个内存池至少有两个地方可以改进。第一,减少对互斥体的消耗,这对嵌入式系统来说是非常有意义的。第二,扩展它使得它能够像appache的内存池一样可以从内存池实例中申请多种规则尺寸的内存块。
使用示例
 
[cpp] view plain copy
 
    
 
1. <span style="color:#ff0000">#include <stdio.h>#include <stdlib.h>#include "elr_mpl.h"int main(){    elr_mpl_t mypool = ELR_MPL_INITIALIZER;    elr_mpl_t mysubpool = ELR_MPL_INITIALIZER;    void*  mem = NULL;     int    len = 0;    elr_mpl_init();         mypool = elr_mpl_create(NULL,256);    printf("%s/n","create a memory pool: mypool.");    mysubpool = elr_mpl_create(&mypool,128);    printf("%s/n","create a sub memory pool of mypool, name is mysubpool.");    mem = elr_mpl_alloc(&mysubpool);    printf("%s/n","alloc a memory <span id="6_nwp" style="width:auto; height:auto; float:none"><a target="_blank" id="6_nwl" href="http://cpro.baidu.com/cpro/ui/uijs.php?adclass=0&app_id=0&c=news&cf=1001&ch=0&di=128&fv=18&is_app=0&jk=96b4ee7ee91c6cbc&k=block&k0=block&kdi0=0&luki=7&mcpm=0&n=10&p=baidu&q=smileking_cpr&rb=0&rs=1&seller_id=1&sid=bc6c1ce97eeeb496&ssp2=1&stid=9&t=tpclicked3_hc&td=1682280&tu=u1682280&u=http%3A%2F%2Fwww%2Eth7%2Ecn%2FProgram%2Fc%2F201403%2F184779%2Eshtml&urlid=0" rel="nofollow" style="text-decoration:none; color:rgb(90,128,238)"><span style="color:rgb(0,0,255); width:auto; height:auto">block</span></a></span> form mysubpool.");    len = elr_mpl_size(mem);    printf("the memory block size is %d./n",len);    elr_mpl_free(mem);    printf("give back the memory block to mysubpool./n",len);    mem = elr_mpl_alloc(&mypool);    printf("%s/n","alloc a memory block form mypool.");    len = elr_mpl_size(mem);    printf("the memory block size is %d./n",len);    elr_mpl_free(mem);    printf("give back the memory <span id="7_nwp" style="width:auto; height:auto; float:none"><a target="_blank" id="7_nwl" href="http://cpro.baidu.com/cpro/ui/uijs.php?adclass=0&app_id=0&c=news&cf=1001&ch=0&di=128&fv=18&is_app=0&jk=96b4ee7ee91c6cbc&k=block&k0=block&kdi0=0&luki=7&mcpm=0&n=10&p=baidu&q=smileking_cpr&rb=0&rs=1&seller_id=1&sid=bc6c1ce97eeeb496&ssp2=1&stid=9&t=tpclicked3_hc&td=1682280&tu=u1682280&u=http%3A%2F%2Fwww%2Eth7%2Ecn%2FProgram%2Fc%2F201403%2F184779%2Eshtml&urlid=0" rel="nofollow" style="text-decoration:none; color:rgb(90,128,238)"><span style="color:rgb(0,0,255); width:auto; height:auto">block</span></a></span> to mypool./n",len);    elr_mpl_destroy(&mypool);    printf("destroy mypool./n",len);    printf("when mypool has destoryed, it`s sub pool, mysubpool, did %s destoryed./n",        elr_mpl_avail(&mysubpool) == 0?"also":"not");    elr_mpl_finalize();    getchar();    return 0;}</span> 
七、跨平台的通用网络通信库:acl 框架库简介
一、概述
acl 工程是一个跨平台的通用网络通信库,同时提供更多的其它有价值功能。通过该库,用户可以非常容易地编写支持多种模式的服务器程序、WEB 应用程序以及数据库应用程序。此外,该库还提供了 XML/JSON/MIME 编码及解码功能,这些编码解码库均支持流式解析模式,从而使之更适应不同的网络通讯方式。
本工程主要包含 5 个库及大量示例。5 个库的说明如下:
1) lib_acl: 该库是最基础的库,其它 4 个库均依赖于该库; 该库以 C 语言实现。
2) lib_protocol: 该库主要实现了 http 协议及 icmp/ping 协议; 该库以 C 语言实现。
3) lib_acl_cpp: 该库用 C++ 语言封装了 lib_acl/lib_protocol 两个库,同时增加了一些其它有价值的功能应用。
4) lib_dict: 该库主要实现了 KEY-VALUE 的字典式存储库,该库另外还依赖于 BDB, CDB 以及 tokyocabinet 库。
5) lib_tls: 该库封装了 openssl 库,使 lib_acl 的通信模式可以支持 ssl。
二、平台支持及编译
整个工程目前支持 Linux(AS4,5,6, CS4,5,6), Windows, MacOS, (原本也支持 FreeBSD, Solaris, 现在如果谁有这些环境,可以轻松移植到这些平台上)。
1) Linux/MacOS: 直接在终端命令行方式下分别进入 lib_acl/lib_protocol/lib_acl_cpp/lib_dict/lib_tls 目录下,运行 make 命令即可。
2) Windows: 可以用 VC2003/VC2010/vc2012 进行编译。(如果您需要用 VC6/VC2005/VC2008 编译,可以参考 VC2003 的编译条件)。
当在 WIN32 环境下使用动态库时有几点需要注意:
a) 使用 lib_acl 的动态库时,需要在用户的工程预定义: ACL_DLL;
b) 使用 lib_protocol 动态库中的 HTTP 库或 ICMP 库时,需要在工程中预定义 HTTP_DLL 、SMTP_DLL或 ICMP_DLL;
c) 使用 lib_acl_cpp 的动态库时,需要在工程中预定义 ACL_CPP_DLL,如果您使用用 VC2003 编译环境则还需要预定义 VC2003;
d) 使用 lib_dict 的动态库时,需要在工程中预定义 DICT_DLL;
e) 使用 lib_tls 的动态库时,需要在工程中预定义 TLS_DLL。
三、本工程目录结构说明
1) lib_acl
init:主要用于初始化 acl 基础库
stdlib:是一些比较基础的功能函数库,在 stdlib/ 根目录下主要包括一些有关日志记录、网络/文件流处理、VSTRING缓冲操作等功能函数;在 stdlib/ 下还有二级目录,如下:
1.2.1 common:该目录主要为一些常用的数据结构及算法的功能函数库,象哈希表、链表、队列、动态数组、堆栈、缓存、平衡二叉树、模式匹配树等;
1.2.2 memory:该目录主要包含与内存操作相关的函数库,象内存基础分配与校验、内存池管理、内存切片管理等;
1.2.3 filedir:该目录主要包含与目录遍历、目录创建等相关的库;
1.2.4 configure:该目录主要包含配置文件的分析库;
1.2.5 iostuff:该目录主要包含一些常用的IO操作的函数库,象读/写超时、设置IO句柄的阻塞模式等;
1.2.6 string:该目录主要包含一些常用的字符串操作的库,提供了比标准C更灵活高效的字符串操作功能;
1.2.7 debug:主要用于协助调试内存的泄露等功能;
1.2.8 sys:主要是与不同操作系统平台相关的API的封装函数库;
net:是与网络操作相关的函数库,包含网络监听、网络连接、DNS查询、套接口参数设置等功能;
1.3.1 connect:主要是与网络连接相关的函数库,包含网络连接、域套接口连接等;
1.3.2 listen:主要是与网络监听相关的函数库,包含网络监听、域套接口监听等;
1.3.3 dns:主要是与DNS域名查询相关的函数库,包含对 gethostbyname 等接口的封装、按RFC1035标准直接发送UDP包方式进行查询等功能;
event:主要封装了 select/poll/epoll/iocp/win message/kqueue/devpoll 等系统API接口,使处理网络事件更加灵活、高效、简单,另外还包含定时器接口,acl 中的很多网络应用都会用到这些接口,象 aio、master 等模块;
aio:主要包含网络异步操作的功能函数,该套函数库在处理高并发时有非常高的效率,而且提供了比基础API更为高级的调用方式,比使用象 libevent 之类的函数库更为简单,而且是线程安全的;
msg:主要包含了基于线程的消息事件及基于网络的消息事件功能;
thread:主要是封装了各个OS平台下的基础线程API,使对外接口保持一致性,消除了平台的差异性,同时还提供了半驻留线程池的函数库,以及对于线程局部变量的扩展;
db:主要是一些与数据库有关的功能库,定义了一个通用的数据库连接池的框架(并且实现了mysql的连接池实例);一个简单的内存数据库(由哈希表、链表、平衡二叉树组合而成);ZDB数据存储引擎,这是一个高效的基于数字键的存储引擎;
proctl:win32
code:常见编码函数库,包括 base64编解码、URL编解码以及一些汉字字符集编码等;
unit_test:包含有关进行 C 语言单元测试的功能库;
xml
json
master:是在 UNIX 环境下支持多种服务器模式的服务器框架,目前主要支持多进程模式、多进程多线程模式、多进程非阻塞模式、UDP通信模式以及多进程触发器模式;
2) lib_protocol
http:HTTP 协议相关的库,支持 HTTP/1.1,通讯方式支持同步/异步方式
2.2 icmp:icmp/ping 协议库,支持同步/异步通信方式
smtp:支持 SMTP 客户端通信库
3) lib_acl_cpp
stdlib:主要包含字符串处理类(string),xml/json 解析库,zlib 压缩库(依赖于 zlib 库), 日志记录类, 字符集转码(在UNIX环境下需要 iconv 库), 线程类/线程池类, 互斥类(支持线程锁、文件锁);
mime:支持完整的与邮件编码相关的库(邮件的 rfc2045-rfc2047/rfc822/base64/uucode 编码及解码库);
master:封装了 C 版 lib_acl 库中的服务器框架,支持进程池模式、线程池模式、非阻塞模式、UDP 通信模式以及触发器模式;
stream:支持网络流/文件流,支持阻塞/非阻塞两种通信方式,在非阻塞模式下支持 select/poll/epoll/iocp/win32 message/kqueue/devpoll;支持 ssl 加密传输(阻塞及非阻塞方式,需要 polarssl库);
ipc:在非阻塞通信方式,提供了阻塞模块与非阻塞模块整合的方式;
http:比较完整的 HTTP 通信库及协议解析库,支持客户端及服务端模式,支持 ssl/gzip 传输方式; 支持类似于 Java HttpServlet 方式的大部分接口,方便编写 CGI 及服务器程序;
db:封装了 MYSQL/SQLITE 库,支持数据库连接池;
hsocket:实现了完整的 handler-socket 客户端通信库;
beanstalk:支持消息队列服务器 beanstalkd 的客户端通信库;
connpool:通用的 TCP 连接池框架;
memcache:支持 memcached 通信协议的客户端库(支持连接池);
queue:磁盘文件队列管理器;
session:会话管理器,目前支持使用 memcache 客户端库存储会话数据。
4) samples:该目录下的程序主要是基于 lib_acl 及 lib_protocol 库的示例
5) lib_acl_cpp/samples:该目录下的程序主要是基于 lib_acl_cpp 库的示例
下载:http://sourceforge.net/projects/acl/
svn:svn checkout svn://svn.code.sf.net/p/acl/code/trunk acl-code
 
 
                     
            
        













 
                    

 
                 
                    