原文地址:https://blog.csdn.net/benpaobagzb/article/details/50814595
一.Think库
提供跨平台的C语言库,各类C、C++程序都可以用到其中的东西,已支持AIX、HP-UX、Solaris、FreeBSD、Linux、Mac OS X和Windows操作系统
本人辛苦了四年,颠覆多次,终成这个发布版,现在作为unix-center的开源项目,任何非册用户进入此链接都可以下载即对每个连接置相应的侦听标志,然后调用think_netselect进行侦听
二.一个跨平台内存分配器
昨天一个同事一大早在群里推荐了一个google project上的开源内存分配器(http://code.google.com/p/google-perftools/),据说google的很多产品都用到了这个内存分配库,而且经他测试,我们的游戏客户端集成了这个最新内存分配器后,FPS足足提高了将近10帧左右,这可是个了不起的提升,要知道3D组的兄弟忙了几周也没见这么大的性能提升。
如果我们自己本身用的crt提供的内存分配器,这个提升也算不得什么。问题是我们内部系统是有一个小内存管理器的,一般来说小内存分配的算法都大同小异,现成的实现也很多,比如linux内核的slab、SGI STL的分配器、ogre自带的内存分配器,我们自己的内存分配器也和前面列举的实现差不多。让我们来看看这个项目有什么特别的吧。
小内存分配器主要作用是“减小内存碎片化趋势,减小薄记内存比例,提高小内存利用率”,从性能上说,系统内存分配器已针对小内存分配进行优化,单纯使用自定义的小内存分配器,对性能帮助不会很大。内置分配器意义还是体现在,实现无锁分配,避免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库
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)
|
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
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;
}
|
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
#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
#include
#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 for (j=0; 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 /* 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 sum += arg[i];
free (arg);
now = time (NULL);
printf ( "--OK. finished. ,
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;
}
|
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:
|
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
#include "stpool.h"
#ifdef _WIN
#include
#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
#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. );
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 ... );
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;
}
|
简介
TBOX是一个用c语言实现的多平台开发库,支持windows、linux、mac、ios、android以及其他嵌入式系统。
针对各个平台,封装了统一的接口,简化了各类开发过程中常用操作,使你在开发过程中,更加关注实际应用的开发,而不是把时间浪费在琐碎的接口兼容性上面,并且充分利用了各个平**有的一些特性进行优化。
针对http、file、socket、data等流数据,实现统一接口进行读写,并且支持: 阻塞、非阻塞、异步 三种读写模式。 支持中间增加多层filter流进行流过滤,实现边读取,内部边进行解压、编码转换、加密等操作,极大的减少了内存使用。
主要提供以下特性:
|
六、一款高效、灵活、跨平台的内存池
项目地址: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的内存池一样可以从内存池实例中申请多种规则尺寸的内存块。
使用示例
七、跨平台的通用网络通信库: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