跨平台C语言开源库总结

2019年12月06日 阅读数:494
这篇文章主要向大家介绍跨平台C语言开源库总结,主要内容包括基础应用、实用技巧、原理机制等方面,希望对大家有所帮助。

一.Think库php

提供跨平台的C语言库,各种C、C++程序均可以用到其中的东西,已支持AIX、HP-UX、Solaris、FreeBSD、Linux、Mac OS X和Windows操做系统 html

本人辛苦了四年,颠覆屡次,终成这个发布版,如今做为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进行侦听node


二.一个跨平台内存分配器mysql

  昨天一个同事一大早在群里推荐了一个google project上的开源内存分配器(http://code.google.com/p/google-perftools/),听说google的不少产品都用到了这个内存分配库,并且经他测试,咱们的游戏客户端集成了这个最新内存分配器后,FPS足足提升了将近10帧左右,这但是个了不得的提高,要知道3D组的兄弟忙了几周也没见这么大的性能提高。

若是咱们本身自己用的crt提供的内存分配器,这个提高也算不得什么。问题是咱们内部系统是有一个小内存管理器的,通常来讲小内存分配的算法都大同小异,现成的实现也不少,好比linux内核的slab、SGI STL的分配器、ogre自带的内存分配器,咱们本身的内存分配器也和前面列举的实现差很少。让咱们来看看这个项目有什么特别的吧。

react

1、使用方法

打开主页,因为公司网络禁止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点不一样:
一、连接器命令行里多了
  "..\..\release\libtcmalloc_minimal.lib",就是连接的时候依赖了这个内存优化库。
二、连接器->输入->强制符号引用 多了 __tcmalloc。
这样就能够正确的使用tcmalloc库了,测试了下,测试项目运行OK!

2、如何替换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函数的,并且仍是经过你们公认的不推荐的改写函数入口指令来实现的,通常只有在游戏外挂和金山词霸之类的软件才会用到这样的挂钩技术,
并且金山词霸常常须要更新补丁解决不一样系统兼容问题。

3、性能差异缘由

如前面所述,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各个线程的内存是独立的,也就是说,第一个线程申请的内存,释放的时候仍是必须放到第一个线程池中(不可移动),这样可能致使大量内存浪费。
 

4、代码细节

一、无缝替换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指令的时候可能会破环后续指令的完整性。

二、LibcInfoWithPatchFunctions 和ThreadCache。

LibcInfoWithPatchFunctions模板类包含tcmalloc实现的优化后的malloc等一系列函数。LibcInfoWithPatchFunctions的模板参数在我看来没什么用处,tcmalloc默承认以挂钩
最多10个带有malloc导出函数的库(我想确定是够用了)。ThreadCache在每一个线程都会有一个TLS对象:
__thread ThreadCache* ThreadCache::threadlocal_heap_。

三、可能的问题


设想下这样一个情景:假若有一个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原始对应函数(这个很重要)释放。这样就解决了这个棘手的问题。

5、其余

其实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
linux

3、跨平台的USB设备访问C语言库,libusb android

libusb的是一个C库,它提供通用的访问USB设备。它支持Linux,Mac OS X,Windows,Windows CE,Android,和OpenBSD/ NetBSD。
跨平台的USB设备访问C语言库,libusb 发布 1.0.18 版本
ios

版本说明:此版本标志着将libusbx项目合并成libusb。c++


4、可直接商用的跨平台c,c++动态线程池,任务池stpool库git

  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<piggy_xrh@163.com>
   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