跨平台C语言开源库总结

原文地址:https://blog.csdn.net/benpaobagzb/article/details/50814595

一.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。
跨平台的USB设备访问C语言库,libusb 发布 1.0.18 版本

版本说明:此版本标志着将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       @email<[email protected]>
   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位)下载:
             http://www.oschina.net/code/snippet_1987090_51468
     
     libstpool3.2 重构框架,支持静态线程池,动态线程池,任务组,框架对特定需求的性能优化具有良好的扩展性和伸缩性
标签: <无>

代码片段(10)[全屏查看所有代码]

1. [文件] libstpool-3.2.rar ~ 4MB     下载(87)     

2. [文件] libstpool.2.6.6库+文档+demo.rar ~ 2MB     下载(126)     

3. [代码]stpool 线程池,任务池     

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
1. 创建一个线程池,服务线程最多不超过5, 预留服务线程为2
      hp = stpool_create(5, 2, 0, 10);
 
  2. 往任务池中添加执行任务.
     struct sttask_t *ptsk = stpool_new_task( "mytask" , mytask_run, mytask_complete, mytask_arg);
  
      stpool_add_task(hp, ptsk);
 
      或者直接可往线程池中添加一个回调或执行路径
         stpool_add_routine(hp, callbak, callback_complete, callback_arg, NULL);
     任务添加后,将会被尽快执行. 同时可使用
         stpool_task_setschattr(ptsk, &attr);
      设置优先级任务,优先级越高的任务越优先调度
 
  3. 等待任务被完成.(stpool 提供对任务的控制,当任务成功加入线程池后,
     可以使用stpool_task_wait来等待任务完成,当用户的task_complete被
     调用完毕后, stpool_task_wait才返回)
 
      stpool_task_wait(hp, ptask, ms);
 
   4. 暂停线程池(线程池被暂停后,除正在被调度的任务外,线程池将不继续执行任务,
                         但仍然可以往线程池中添加任务,只是这些任务都处于排队状态)
       stpool_suspend(hp, 0).
 
   5. 恢复线程池的运行.
       stpool_resume(hp);
 
   6. 禁止用户继续向线程池投递任务(用户调用@tpool_add_task时会返回POOL_ERR_THROTTLE错误码)
       tpool_throttle_enable(hp, 1)
   
   7. 等待何时可以投递任务
       stpool_throttle_wait(hp, ms);
 
   8. 线程池服务线程数量控制
       .) 重新设置线程池最大数量为2,预留线程为0
            stpool_adjust_abs(hp, 2, 0);
 
       .)在原来的基础上,将线程池最大服务线程数量+1, 最小数量-1
          (这并不代表stpool马上会创建线程,而只是在任务繁重的时候内部精心调度开启)
            stpool_adjust(hp, 1, -1)
 
   9. 获取任务池的状态
       .)获取stpool内服务线程数目,任务执行情况
          struct stpool_stat_t stat;
 
          stpool_getstat(hp, &stat);
       .)获取任务的状态
          long stat = stpool_gettskstat(hp,  &mytask);
        
       .) 访问线程池中的所有任务状态
          stpool_mark_task(hp, mark_walk, arg)
 
   10.移除所有在等待的任务
        stpool_remove_pending_task(hp, NULL);
 
   11.提供引用计数,线程可被其它模块使用,确保线程池对象的生命周期.
        第三方模块使用线程池.
 
         stpool_addref(hp)        //保证线程池对象不会被销毁
         stpool_adjust(hp, 2, 0);  //添加本模块的需求(增大最大服务线程数+2)
         //投递本模块的任务
         stpool_release(hp)       //释放线程池
 
   12. 销毁线程池.(当引用计数为0时候,线程池对象会被自动释放,
                            @stpool_create成功后其用户引用计数为1)
         stpool_release(hp)

4. [文件] demo-c++.cpp ~ 3KB     下载(12)     

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
/* COPYRIGHT (C) 2014 - 2020, piggy_xrh */
#include <iostream>
using namespace std;
 
#include "CTaskPool.h"
 
#ifdef _WIN
#ifdef _DEBUG
#ifdef _WIN64
#pragma comment(lib, "../../../lib/Debug/x86_64_win/libmsglog.lib")
#pragma comment(lib, "../../../lib/Debug/x86_64_win/libstpool.lib")
#pragma comment(lib, "../../../lib/Debug/x86_64_win/libstpoolc++.lib")
#else
#pragma comment(lib, "../../../lib/Debug/x86_32_win/libmsglog.lib")
#pragma comment(lib, "../../../lib/Debug/x86_32_win/libstpool.lib")
#pragma comment(lib, "../../../lib/Debug/x86_32_win/libstpoolc++.lib")
#endif
#else
#ifdef _WIN64
#pragma comment(lib, "../../../lib/Release/x86_64_win/libmsglog.lib")
#pragma comment(lib, "../../../lib/Release/x86_64_win/libstpool.lib")
#pragma comment(lib, "../../../lib/Release/x86_64_win/libstpoolc++.lib")
#else
#pragma comment(lib, "../../../lib/Release/x86_32_win/libmsglog.lib")
#pragma comment(lib, "../../../lib/Release/x86_32_win/libstpool.lib")
#pragma comment(lib, "../../../lib/Release/x86_32_win/libstpoolc++.lib")
#endif
#endif
#endif
 
/* (log library)    depends  (task pool library)   depends    (task pool library for c++)
  * libmsglog.lib <-------------libstpool.lib <--------------------libstpoolc++.lib
*/
class myTask: public CTask
{
     public :
         /* We can allocate a block manually for the proxy object.
          * and we can retreive its address by @getProxy()
          */
         myTask(): CTask( /*new char[getProxySize()]*/ NULL,  "mytask" ) {}
         ~myTask()
         {
             /* NOTE: We are responsible for releasing the proxy object if
              * the parameter @cproxy passed to CTask is NULL */
             if (isProxyCreatedBySystem())
                 freeProxy(getProxy());
             
             else
                 delete []  reinterpret_cast < char *>(getProxy());
         }
 
     private :
         virtual int onTask()
         {
             cout << taskName() <<  ": onTask.\n" ;
             return 0;
         }
 
         virtual void  onTaskComplete( long sm,  int errCode)
         {
             if (CTask::sm_DONE & sm)
                 cout << taskName() <<  " has been done with code:"  << dec << errCode
                      << "  stat:0x"  << hex << stat() <<  " sm:0x"  << sm << endl;
                    
             else
                 cerr << taskName() <<  " has not been done. reason:"  << dec << errCode
                      << "  stat:0x"  << hex << stat() <<  " sm:0x"  << sm << endl;
             
             static int slTimes = 0;
             /*      We reschedule the task again.
              * NOTE:
              *      task->wait() will not return until the task
              *  does not exist in both the pending pool and the
              *  scheduling queue.
              */
             if (++ slTimes < 5)
                 queue();   
 
             /* The task will be marked with @sm_ONCE_AGAIN if user calls
              * @queue to reschedule it while it is being scheduled. and
              * @sm_ONCE_AGAIN will be removed by the pool after it having
              * been delived into the pool. */
             cout << dec << slTimes <<  "  sm:0x"  << hex <<  this ->sm() << endl << endl;
         }
};
 
int main()
{
     /* Create a pool instance with 1 servering thread */
     CTaskPool *pool = CTaskPool::createInstance(1, 0,  false );  
     
     /* Test running the task */
     myTask *task =  new myTask;
     
     /* Set the task's parent before our's calling @queue */
     task->setParent(pool);
     
     /* Deliver the task into the pool */
     task->queue();  
     
     /* Wait for the task's being done */
     task->wait();
     
     cout <<  "\ntask has been done !"  << endl;
 
     /* Free the task object */
     delete task;
     
     /* Shut down the pool */
     pool->release();
     
     cin.get();
     return 0;
}

5. [图片] linux_win_demo-c++.png    

6. [文件] demo-sche.c ~ 3KB     下载(8)     

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
/* COPYRIGHT (C) 2014 - 2020, piggy_xrh */
 
#include <stdio.h>
 
#include "stpool.h"
 
#ifdef _WIN
 
#ifdef _DEBUG
#ifdef _WIN64
#pragma comment(lib, "../../../lib/Debug/x86_64_win/libmsglog.lib")
#pragma comment(lib, "../../../lib/Debug/x86_64_win/libstpool.lib")
#else
#pragma comment(lib, "../../../lib/Debug/x86_32_win/libmsglog.lib")
#pragma comment(lib, "../../../lib/Debug/x86_32_win/libstpool.lib")
#endif
#else
#ifdef _WIN64
#pragma comment(lib, "../../../lib/Release/x86_64_win/libmsglog.lib")
#pragma comment(lib, "../../../lib/Release/x86_64_win/libstpool.lib")
#else
#pragma comment(lib, "../../../lib/Release/x86_32_win/libmsglog.lib")
#pragma comment(lib, "../../../lib/Release/x86_32_win/libstpool.lib")
#endif
#endif
 
#else
#include <stdint.h>
#include <sys/time.h>
#endif
 
/* (log library)    depends  (task pool library)
  * libmsglog.lib <-------------libstpool.lib
*/
static void do_work( int *val) {
     *val += 100;
     *val *= 0.371;
}
 
int  task_run( struct sttask_t *ptsk) {
     size_t i, j, sed = 20;
     
     for (i=0; i<sed; i++)
         for (j=0; j<sed; j++)
             do_work(( int *)ptsk->task_arg);
     
     /* Do not call @printf in the test since it will waste our
      * so much time on competing the IO.
      */
     return 0;
}
 
void task_complete( struct sttask_t *ptsk,  long vmflags,  int code) {
}
 
int main()
{
     time_t now;
     int i, c, times, j=0;
     int sum, *arg;
     HPOOL hp;
         
     /* Creat a task pool */
     hp = stpool_create(50,   /* max servering threads */
                        0,   /* 0 servering threads that reserved for waiting for tasks */
                        1,   /* suspend the pool */
                        0);  /* default number of priority queue */
     printf ( "%s\n" , stpool_status_print(hp, NULL, 0));
     
     /* Add tasks */
     times = 90000;
     arg = ( int *) malloc (times *  sizeof ( int ));
     for (i=0; i<times; i++) {
         /* It may take a long time to load a large amount of tasks
          * if the program is linked with the debug library */
         if (i % 4000 == 0 || (i + 1) ==times) {
             printf ( "\rLoading ... %.2f%%  " , ( float )i * 100/ times);
             fflush (stdout);
         }
         arg[i] = i;
         stpool_add_routine(hp, "sche" , task_run, task_complete, ( void *)&arg[i], NULL);
     }
     printf ( "\nAfter having executed @stpool_add_routine for %d times:\n"
            "--------------------------------------------------------\n%s\n" ,
            times, stpool_status_print(hp, NULL, 0));
     
     printf ( "Press any key to resume the pool.\n" );
     getchar ();
     
     /* Wake up the pool to schedule tasks */
     stpool_resume(hp);     
     stpool_task_wait(hp, NULL, -1);
         
     /* Get the sum */
     for (i=0, sum=0; i<times; i++)
         sum += arg[i];
     free (arg);
     
     now =  time (NULL);
     printf ( "--OK. finished. <arg: %d> %s\n%s\n" ,
         sum, ctime (&now), stpool_status_print(hp, NULL, 0));
#if 0
     /* You can use debug library to watch the status of the pool */
     while ( 'q' !=  getchar ()) {
         for (i=0; i<40; i++)
             stpool_add_routine(hp, "debug" , task_run, NULL, &sum, NULL);   
     }
 
     /* Clear the stdio cache */
     while ((c= getchar ()) && c !=  '\n' && c != EOF)
         ;
#endif
     getchar ();
     /* Release the pool */
     printf ( "Shut down the pool now.\n" );
     stpool_release(hp);
     getchar ();
         
     return 0;
}

7. [图片] win32_linux_demo_sche1.jpg    

8. [图片] win32_linux_demo_sche2.jpg    

9. [代码]demo-sche结果分析     

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
    线程和任务峰值统计(现仅统计win32/linux)
 
             win32(xp)                  linux(ubuntu 10.04)
    ----------------------------------------------------
         threads_peak: 9              threads_peak: 6
           tasks_peak: 90000            tasks_peak: 90000
    ------------------------------------------------------
     完成90000个任务,stpool最高峰线程数目为9(win32),6(linux),根据任务
执行情况智能调度任务,90000个任务都在1s内完成.
     (ubuntu为xp的vmware虚拟机, 运行设置为2核2线程)
 
root@ubuntu_xrh:~/localhost/task/stpool# cat /proc/cpuinfo
processor   : 0
vendor_id   : GenuineIntel
cpu family  : 6
model       : 42
model name  : Intel(R) Pentium(R) CPU G620 @ 2.60GHz
stepping    : 7
cpu MHz     : 2594.108
cache size  : 3072 KB
fdiv_bug    : no
hlt_bug     : no
f00f_bug    : no
coma_bug    : no
fpu     : yes
fpu_exception   : yes
cpuid level : 13
wp      : yes
flags       : fpu vme de pse tsc msr pae mce cx8 apic mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss nx rdtscp constant_tsc arch_perfmon pebs bts xtopology tsc_reliable nonstop_tsc aperfmperf pni pclmulqdq ssse3 sse4_1 sse4_2 popcnt hypervisor arat
bogomips    : 5188.21
clflush size    : 64
cache_alignment : 64
address sizes   : 40 bits physical, 48 bits  virtual
power management:
 
processor   : 1
vendor_id   : GenuineIntel
cpu family  : 6
model       : 42
model name  : Intel(R) Pentium(R) CPU G620 @ 2.60GHz
stepping    : 7
cpu MHz     : 2594.108
cache size  : 3072 KB
fdiv_bug    : no
hlt_bug     : no
f00f_bug    : no
coma_bug    : no
fpu     : yes
fpu_exception   : yes
cpuid level : 13
wp      : yes
flags       : fpu vme de pse tsc msr pae mce cx8 apic mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss nx rdtscp constant_tsc arch_perfmon pebs bts xtopology tsc_reliable nonstop_tsc aperfmperf pni pclmulqdq ssse3 sse4_1 sse4_2 popcnt hypervisor arat
bogomips    : 5188.21
clflush size    : 64
cache_alignment : 64
address sizes   : 40 bits physical, 48 bits  virtual
power management:

10. [文件] demo.c ~ 7KB     下载(9)     

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
/* COPYRIGHT (C) 2014 - 2020, piggy_xrh */
 
#include <stdio.h>
#include "stpool.h"
 
#ifdef _WIN
 
#include <Windows.h>
#define msleep Sleep
#ifdef _DEBUG
#ifdef _WIN64
#pragma comment(lib, "../../../lib/Debug/x86_64_win/libstpool.lib")
#else
#pragma comment(lib, "../../../lib/Debug/x86_32_win/libstpool.lib")
#endif
#else
#ifdef _WIN64
#pragma comment(lib, "../../../lib/Release/x86_64_win/libstpool.lib")
#else
#pragma comment(lib, "../../../lib/Release/x86_32_win/libstpool.lib")
#endif
#endif
 
#else
#include <stdint.h>
#define msleep(x) usleep(x * 1000)
#endif
 
static int g_test_reschedule = 0;
 
int task_run( struct sttask_t *ptsk) {
     /* TO DO */
     printf ( "@task_run ...:%d\n" , *( int *)ptsk->task_arg);   
 
     ++ *( int *)ptsk->task_arg;
     //msleep(3000);
     
     return 0;
}
 
void task_complete( struct sttask_t *ptsk,  long vmflags ,  int task_code) {      
     /* NOTE:
      *     If vmflags has been marked with STTASK_VMARK_DONE, it indicates that
      *   the @task_run has been excuted by the pool.
      */
     if (!(STTASK_VMARK_DONE & vmflags)) {
         printf ( "@task_run is not executed: 0x%lx-code:%d\n" ,
                vmflags, task_code  /* STPOOL_XX */ );
         
         return ;
     }
         
     if (g_test_reschedule) {
         struct schattr_t attr;
         
         /* We sleep for a while to slow down the test */
         msleep(1500);
 
         /* We adjust the task's priority */
         stpool_task_getschattr(ptsk, &attr);
         if (!attr.permanent) {
             attr.permanent = 1;
             attr.sche_pri  = 80;
             stpool_task_setschattr(ptsk, &attr);
         }
             
         /* Reschedule the task */
         stpool_add_task(ptsk->hp_last_attached, ptsk);
     }  
}
 
static int counter = 0;
 
int task_run2( struct sttask_t *ptsk) {
     static int i=0;
 
     printf ( "@task_run2: %d\n" , ++i);
     return 0;
}
 
void task_complete2( struct sttask_t *ptsk,  long vmflags,  int task_code) {  
     if (!(STTASK_VMARK_DONE & vmflags)) {
         printf ( "@task_run2 is not executed: 0x%lx-code:%d\n" ,
             vmflags, task_code);
         return ;
     }
     
     if (g_test_reschedule) {
         msleep(1500);
         
         /* Reschedule the task */
         stpool_add_task(ptsk->hp_last_attached, ptsk);
     }
}
 
long mark_walk( struct stpool_tskstat_t *stat,  void *arg) {
     /* If you want to stop walking the task, you should return -1 */
     //return -1;
     
     /* If you just want to walk the tasks, you should return 0 */
     //return 0;
 
     /* Return the marks */
     return STTASK_VMARK_REMOVE_BYPOOL  /* Remove the task */
            ;
}
 
int main()
{
     int i, error;
     HPOOL hp;
     struct schattr_t attr = {
         0, 1, STP_SCHE_TOP
     }; 
     struct sttask_t *ptsk;
     
     /* NO buffer */
     setbuf (stdout, 0);
     
     /* Create a pool */
     hp = stpool_create(20,  /*limited threads number*/
                        0,  /*number of threads reserved to waiting for tasks*/
                        0,  /*do not suspend the pool */
                        1   /*priority queue num */
                        );
     
     /* Set the sleep time for the threads (10s + random() % 60s)*/
     stpool_set_activetimeo(hp, 10, 20);
     
     /* Print the status of the pool */
     printf ( "@tpool_create(20, 0, 0, 10)\n%s\n" , stpool_status_print(hp, NULL, 0));
         
     /************************************************************/
     /********************Test @stpool_adjust(_abs)****************/
     /************************************************************/
     printf ( "\nPress any key to test the @tpool_adjust(abs) ....\n" );
     getchar ();
     stpool_adjust_abs(hp, 300, 1);
     printf ( "@tpool_adjust_abs(pool, 300, 1)\n%s\n" , stpool_status_print(hp, NULL, 0));
     
     /* We call @stpool_adjust to recover the pool env */
     stpool_adjust(hp, -280, -1);
     stpool_adjust_wait(hp);
     printf ( "@tpool_adjust(pool, -280, -1)\n%s\n" , stpool_status_print(hp, NULL, 0));
     
     /*******************************************************************/
     /********************Test the throttle******************************/
     /*******************************************************************/
     printf ( "\nPress any key to test the throttle ....\n" );
     getchar ();
     /* Turn the throttle on */
     stpool_throttle_enable(hp, 1);
     ptsk = stpool_task_new( "test" , task_run, task_complete, ( void *)&counter);
     error = stpool_add_task(hp, ptsk);
     if (error)
         printf ( "***@stpool_add_task error:%d\n" , error);
     /* Turn the throttle off */
     stpool_throttle_enable(hp, 0);
     
     /*******************************************************************/
     /******************Test the priority********************************/
     /*******************************************************************/
     printf ( "\nPress any key to test the priority ....\n" );
     getchar ();
     
     stpool_suspend(hp, 0);
     /* Add a task with zero priority, and the task will be pushed into the
      * lowest priority queue.
      */
     stpool_add_routine(hp, "test" , task_run, task_complete, ( void *)&counter, NULL);
         
     /* @task_run2 will be scheduled prior to the @task_run since the @task_run2 has
      * a higher priority.
      */
     stpool_add_routine(hp, "routine" , task_run2, task_complete2, NULL, &attr);
     
     /* Wake up the pool to schedule the tasks */
     stpool_resume(hp);
 
     /* Wait for all tasks' being done completely */
     stpool_task_wait(hp, NULL, -1);
     
     /******************************************************************/
     /****************Test rescheduling task****************************/
     /******************************************************************/
     printf ( "\nPress any key to test rescheduling task. <then press key to stop testing.>\n" );
     getchar ();
     g_test_reschedule = 1;
     stpool_add_task(hp, ptsk);
     stpool_add_routine(hp, "routine" , task_run2, task_complete2, NULL, NULL);
     
     getchar ();
     g_test_reschedule = 0; 
     stpool_task_wait(hp, NULL, -1);
     
     /******************************************************************/
     /***************Test running amount of tasks***********************/
     /******************************************************************/
     printf ( "\nPress any key to add tasks ... <then can press any key to remove them.>\n" );
     getchar ();
     
     /* We can suspend the pool firstly, and then resume the pool after delivering our
      * tasks into the pool, It'll be more effecient to do it like that if there are 
      * a large amount of tasks that will be added into the pool.
      */
     /* NOTE: We can add the same task into the pool one more times */
     for (i=0; i<4000; i++) {
         stpool_add_routine(hp, "test" , task_run, task_complete, ( void *)&counter, NULL);
         stpool_add_routine(hp, "routine" , task_run2, task_complete2, NULL, NULL);
     }
     
     /****************************************************************/
     /*************Test stoping all tasks fastly**********************/
     /****************************************************************/
     printf ( "\nPress any key to test stoping all tasks fastly.\n" );
     getchar ();
 
     /* Remove all pending tasks by calling @stpool_mark_task_ex,
      * We can also call @stpool_remove_pending_task to reach our
      * goal, But we call @stpool_mark_task_ex here for showing
      * how to use @stpool_mark_task to do the customed works.
      */
     stpool_mark_task_ex(hp, mark_walk, NULL);
     stpool_throttle_enable(hp, 1);
 
     /* Wait for all tasks' being done */
     stpool_task_wait(hp, NULL, -1);
     printf ( "---------------------------tasks have been finished.\n" );
     
     /* Free the task object */
     stpool_task_delete(ptsk);
         
     /* Release the pool */
     printf ( "%s\n" , stpool_status_print(hp, NULL, 0));
     stpool_release(hp);
     printf ( "Press any key to exit ...\n" );
     getchar ();
     
     return 0;
}
五、一个轻量级跨平台c开发库:TBOX

简介
TBOX是一个用c语言实现的多平台开发库,支持windows、linux、mac、ios、android以及其他嵌入式系统。
针对各个平台,封装了统一的接口,简化了各类开发过程中常用操作,使你在开发过程中,更加关注实际应用的开发,而不是把时间浪费在琐碎的接口兼容性上面,并且充分利用了各个平**有的一些特性进行优化。
流库
针对http、file、socket、data等流数据,实现统一接口进行读写,并且支持: 阻塞、非阻塞、异步 三种读写模式。 支持中间增加多层filter流进行流过滤,实现边读取,内部边进行解压、编码转换、加密等操作,极大的减少了内存使用。
主要提供以下特性:
  • stream:通用非阻塞流,用于一般的单独io处理。
  • async_stream:利用asio实现的纯异步流,基于回调模式,可同时处理大量并发io。
  • transfer:传输器,维护两路流的传输,对async_stream的使用进行更上层的封装,用其可以很方便的实现下载、上传、复制等io传输操作。
  • transfer_pool:传输池,基于asio,维护大量并发的传输,可以用于实现爬虫、批量下载等等。
  • static_stream:针对静态数据buffer优化的静态流,用于轻量快速的数据解析。
asio库
  • 支持reactor和proactor两种模型,针对不同平台,采用epoll/poll/select/kqueue/iocp接口,最大化异步操作的性能。
  • 并且对http、ssl、dns也提供了纯异步模式的实现。基于此库完全可以很方便的写出一个高性能的小型服务器。
数据库
  • 统一并简化数据库操作接口,适配各种数据源,通过统一的url来自动连接打开支持的数据库,数据的枚举采用迭代器模型。
  • 目前支持sqlite3以及mysql两种关系型数据库,也可自定义扩展使用其他关系型数据库。
xml库
  • 针对xml提供DOM和SAX两种解析模式,SAX方式采用外部迭代模式,灵活性和性能更高,并且可以选择指定路径,进行解析。
  • 解析过程完全基于stream,所以是高度流化的,可以实现边下载、边解压、边转码、边解析一条龙服务,使用较低的内存也可以解析大规模数据。
  • 提供xml writer以支持对xml生成
内存库
  • 参考linux内核内存管理机制的实现,并对其进行各种改造和优化,所实现的TBOX独有的一整套内存池管理架构。
  • 调试模式下,可以轻松检测并定位内存泄露、内存越界溢出、内存重叠覆盖等常见内存问题,并对整体内存的使用进行了统计和简要分析。
  • 针对大块数据、小块数据、字符串数据进行了充分的利用,避免了大量外部碎片和内部碎片的产生。分配操作进行了各种优化,96%的情况下,效率都是在O(1)。
容器库
  • 提供哈希、链表、数组、队列、堆栈、最小最大堆等常用容器。
  • 支持各种常用成员类型,在原有的容器期初上,其成员类型还可以完全自定义扩展。
  • 所有容器都支持迭代器操作。
  • 大部分容器都可以支持基于stream的序列化和反序列化操作。
算法库
  • 提供各种排序算法:冒泡排序、堆排序、快速排序、插入排序。
  • 提供各种查找算法:线性遍历、二分法搜索。
  • 提供各种遍历、删除、统计算法。
  • 以迭代器为接口,实现算法和容器的分离,类似stl,但是c实现的,更加轻量。
网络库
  • 实现http、cookies、dns解析与缓存、ipv4、url的封装。
数**算库
  • 提供各种精度的定点运算支持
  • 提供随机数生成器
libc库
  • libc的一个轻量级实现,完全跨平台,并且针对不同架构进行了优化。
  • 支持大部分字符串、宽字符串操作。
  • 扩展字符串、宽字符串的各种大小写不敏感操作接口
  • 扩展memset_u16、memset_u32等接口,并对其进行高度优化,尤其适合图形渲染程序
libm库
  • libm部分接口的一个轻量级实现,以及对常用系统接口的封装。(目前只实现了部分,之后有时间会完全实现掉)
  • 扩展部分常用接口,增加对sqrt、log2等常用函数的整数版本计算,进行高度优化,不涉及浮点运算,适合嵌入式环境使用。
object库
  • 轻量级类apple的CoreFoundation库,支持object、dictionary、array、string、number、date、data等常用对象,并且可以方便扩展自定义对象的序列化。
  • 支持对xml、json、binary以及apple的plist(xplist/bplist)格式序列化和反序列化。 并且实现自有的binary序列化格式, 针对明文进行了简单的加密,在不影响性能的前提下,序列化后的大小比bplist节省30%。
平台库
  • 提供file、directory、socket、thread、time等常用系统接口
  • 提供atomic、atomic64接口
  • 提供高精度、低精度定时器
  • 提供高性能的线程池操作
  • 提供event、mutex、semaphore、spinlock等事件、互斥、信号量、自旋锁操作
  • 提供获取函数堆栈信息的接口,方便调试和错误定位
  • 提供跨平台动态库加载接口(如果系统支持的话)
压缩库
  • 支持zlib/zlibraw/gzip的压缩与解压(需要第三方zlib库支持)。
字符编码库
  • 支持utf8、utf16、gbk、gb2312、uc2、uc4 之间的互相转码,并且支持大小端格式。
实用工具库
  • 实现base64/32编解码
  • 实现crc32、adler32、md5、sha1等常用hash算法
  • 实现日志输出、断言等辅助调试工具
  • 实现url编解码
  • 实现位操作相关接口,支持各种数据格式的解析,可以对8bits、16bits、32bits、64bits、float、double以及任意bits的字段进行解析操作,并且同时支持大端、小端和本地端模式,并针对部分操作进行了优化,像static_stream、stream都有相关接口对其进行了封装,方便在流上进行快速数据解析。
  • 实现swap16、swap32、swap64等位交换操作,并针对各个平台进行了优化。
  • 实现一些高级的位处理接口,例如:位0的快速统计、前导0和前导1的快速位计数、后导01的快速位计数
  • 实现单例模块,可以对静态对象、实例对象进行快速的单例封装,实现全局线程安全
  • 实现option模块,对命令行参数进行解析,提供快速方便的命令行选项建立和解析操作,对于写终端程序还是很有帮助的


六、一款高效、灵活、跨平台的内存池

项目地址: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

    1.1 init:主要用于初始化 acl 基础库

    1.2 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的封装函数库;

    1.3 net:是与网络操作相关的函数库,包含网络监听、网络连接、DNS查询、套接口参数设置等功能;

    1.3.1 connect:主要是与网络连接相关的函数库,包含网络连接、域套接口连接等;

    1.3.2 listen:主要是与网络监听相关的函数库,包含网络监听、域套接口监听等;

    1.3.3 dns:主要是与DNS域名查询相关的函数库,包含对 gethostbyname 等接口的封装、按RFC1035标准直接发送UDP包方式进行查询等功能;

    1.4 event:主要封装了 select/poll/epoll/iocp/win message/kqueue/devpoll 等系统API接口,使处理网络事件更加灵活、高效、简单,另外还包含定时器接口,acl 中的很多网络应用都会用到这些接口,象 aio、master 等模块;

    1.5 aio:主要包含网络异步操作的功能函数,该套函数库在处理高并发时有非常高的效率,而且提供了比基础API更为高级的调用方式,比使用象 libevent 之类的函数库更为简单,而且是线程安全的;

    1.6 msg:主要包含了基于线程的消息事件及基于网络的消息事件功能;

    1.7 thread:主要是封装了各个OS平台下的基础线程API,使对外接口保持一致性,消除了平台的差异性,同时还提供了半驻留线程池的函数库,以及对于线程局部变量的扩展;

    1.8 db:主要是一些与数据库有关的功能库,定义了一个通用的数据库连接池的框架(并且实现了mysql的连接池实例);一个简单的内存数据库(由哈希表、链表、平衡二叉树组合而成);ZDB数据存储引擎,这是一个高效的基于数字键的存储引擎;

    1.9 proctl:win32 平台下父子进程控制功能库;

    1.10 code:常见编码函数库,包括 base64编解码、URL编解码以及一些汉字字符集编码等;

    1.11 unit_test:包含有关进行 C 语言单元测试的功能库;

    1.12 xml :是一个流式的 xml 解析器及构造器,可以支持阻塞及阻塞式网络通信;

    1.13 json :是一个流式的 json 解析器及构造器,可以支持阻塞及阻塞式网络通信;

    1.14 master:是在 UNIX 环境下支持多种服务器模式的服务器框架,目前主要支持多进程模式、多进程多线程模式、多进程非阻塞模式、UDP通信模式以及多进程触发器模式;

 

    2) lib_protocol

    2.1 http:HTTP 协议相关的库,支持 HTTP/1.1,通讯方式支持同步/异步方式

    2.2 icmp:icmp/ping 协议库,支持同步/异步通信方式

    2.3 smtp:支持 SMTP 客户端通信库

 

    3) lib_acl_cpp

    3.1 stdlib:主要包含字符串处理类(string),xml/json 解析库,zlib 压缩库(依赖于 zlib 库), 日志记录类, 字符集转码(在UNIX环境下需要 iconv 库), 线程类/线程池类, 互斥类(支持线程锁、文件锁);

    3.2 mime:支持完整的与邮件编码相关的库(邮件的 rfc2045-rfc2047/rfc822/base64/uucode 编码及解码库);

    3.3 master:封装了 C 版 lib_acl 库中的服务器框架,支持进程池模式、线程池模式、非阻塞模式、UDP 通信模式以及触发器模式;

    3.4 stream:支持网络流/文件流,支持阻塞/非阻塞两种通信方式,在非阻塞模式下支持 select/poll/epoll/iocp/win32 message/kqueue/devpoll;支持 ssl 加密传输(阻塞及非阻塞方式,需要 polarssl库);

    3.5 ipc:在非阻塞通信方式,提供了阻塞模块与非阻塞模块整合的方式;

    3.6 http:比较完整的 HTTP 通信库及协议解析库,支持客户端及服务端模式,支持 ssl/gzip 传输方式; 支持类似于 Java HttpServlet 方式的大部分接口,方便编写 CGI 及服务器程序;

    3.7 db:封装了 MYSQL/SQLITE 库,支持数据库连接池;

    3.8 hsocket:实现了完整的 handler-socket 客户端通信库;

    3.9 beanstalk:支持消息队列服务器 beanstalkd 的客户端通信库;

    3.10 connpool:通用的 TCP 连接池框架;

    3.11 memcache:支持 memcached 通信协议的客户端库(支持连接池);

    3.12 queue:磁盘文件队列管理器;

    3.13 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

github:https://github.com/zhengshuxin/acl

猜你喜欢

转载自blog.csdn.net/qq_31776303/article/details/80696725