﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-michael-随笔分类-C++ programme language</title><link>http://www.cppblog.com/michaelgao/category/7305.html</link><description /><language>zh-cn</language><lastBuildDate>Mon, 02 Feb 2009 23:56:50 GMT</lastBuildDate><pubDate>Mon, 02 Feb 2009 23:56:50 GMT</pubDate><ttl>60</ttl><item><title>C++线程池的概念</title><link>http://www.cppblog.com/michaelgao/archive/2009/02/02/72810.html</link><dc:creator>micheal's tech</dc:creator><author>micheal's tech</author><pubDate>Mon, 02 Feb 2009 08:28:00 GMT</pubDate><guid>http://www.cppblog.com/michaelgao/archive/2009/02/02/72810.html</guid><wfw:comment>http://www.cppblog.com/michaelgao/comments/72810.html</wfw:comment><comments>http://www.cppblog.com/michaelgao/archive/2009/02/02/72810.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/michaelgao/comments/commentRss/72810.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/michaelgao/services/trackbacks/72810.html</trackback:ping><description><![CDATA[<div id="header">
<div id="HeaderTitle">
<div id="Title">
<a id="Header1_HeaderTitle" class="headermaintitle" href="http://www.cnblogs.com/phinecos/">Phinecos(洞庭散人)</a>
</div>
<div id="subTitle">光荣在于平淡，艰巨因为漫长</div>
</div>
</div>
<script type="text/javascript">
//<![cdata[
sys.webforms.pagerequestmanager._initialize('ajaxholder$scriptmanager1', document.getElementById('Form1'));
Sys.WebForms.PageRequestManager.getInstance()._updateControls(['tAjaxHolder$UpdatePanel1'], [], [], 90);
//]]&gt;
</script>
<h2>
<a id="AjaxHolder_ctl01_TitleUrl" href="http://www.cnblogs.com/phinecos/archive/2008/11/08/1329520.html">【转】一个简单的线程池（c++版）</a>
</h2>
<div class="cnblogs_code">#ifndef&nbsp;_ThreadPool_H_<br>
#define&nbsp;_ThreadPool_H_<br>
#pragma&nbsp;warning(disable:&nbsp;4530)<br>
#pragma&nbsp;warning(disable:&nbsp;4786)<br>
#include&nbsp;&lt;cassert&gt;<br>
#include&nbsp;&lt;vector&gt;<br>
#include&nbsp;&lt;queue&gt;<br>
#include&nbsp;&lt;windows.h&gt;<br>
class&nbsp;ThreadJob&nbsp;&nbsp;//工作基类<br>
{<br>
public:<br>
&nbsp;&nbsp;&nbsp;&nbsp;//供线程池调用的虚函数<br>
&nbsp;&nbsp;&nbsp;&nbsp;virtual&nbsp;void&nbsp;DoJob(void&nbsp;*pPara)&nbsp;=&nbsp;0;<br>
};<br>
class&nbsp;ThreadPool<br>
{<br>
public:<br>
&nbsp;&nbsp;&nbsp;&nbsp;//dwNum&nbsp;线程池规模<br>
&nbsp;&nbsp;&nbsp;&nbsp;ThreadPool(DWORD&nbsp;dwNum&nbsp;=&nbsp;4)&nbsp;:&nbsp;_lThreadNum(0),&nbsp;_lRunningNum(0)<br>
&nbsp;&nbsp;&nbsp;&nbsp;{<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;InitializeCriticalSection(&amp;_csThreadVector);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;InitializeCriticalSection(&amp;_csWorkQueue);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_EventComplete&nbsp;=&nbsp;CreateEvent(0,&nbsp;false,&nbsp;false,&nbsp;NULL);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_EventEnd&nbsp;=&nbsp;CreateEvent(0,&nbsp;true,&nbsp;false,&nbsp;NULL);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_SemaphoreCall&nbsp;=&nbsp;CreateSemaphore(0,&nbsp;0,&nbsp;&nbsp;0x7FFFFFFF,&nbsp;NULL);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_SemaphoreDel&nbsp;=&nbsp;&nbsp;CreateSemaphore(0,&nbsp;0,&nbsp;&nbsp;0x7FFFFFFF,&nbsp;NULL);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;assert(_SemaphoreCall&nbsp;!=&nbsp;INVALID_HANDLE_VALUE);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;assert(_EventComplete&nbsp;!=&nbsp;INVALID_HANDLE_VALUE);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;assert(_EventEnd&nbsp;!=&nbsp;INVALID_HANDLE_VALUE);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;assert(_SemaphoreDel&nbsp;!=&nbsp;INVALID_HANDLE_VALUE);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;AdjustSize(dwNum&nbsp;&lt;=&nbsp;0&nbsp;?&nbsp;4&nbsp;:&nbsp;dwNum);<br>
&nbsp;&nbsp;&nbsp;&nbsp;}<br>
&nbsp;&nbsp;&nbsp;&nbsp;~ThreadPool()<br>
&nbsp;&nbsp;&nbsp;&nbsp;{<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DeleteCriticalSection(&amp;_csWorkQueue);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CloseHandle(_EventEnd);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CloseHandle(_EventComplete);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CloseHandle(_SemaphoreCall);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CloseHandle(_SemaphoreDel);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;vector&lt;ThreadItem*&gt;::iterator&nbsp;iter;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for(iter&nbsp;=&nbsp;_ThreadVector.begin();&nbsp;iter&nbsp;!=&nbsp;_ThreadVector.end();&nbsp;iter++)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(*iter)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;delete&nbsp;*iter;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DeleteCriticalSection(&amp;_csThreadVector);<br>
&nbsp;&nbsp;&nbsp;&nbsp;}<br>
&nbsp;&nbsp;&nbsp;&nbsp;//调整线程池规模<br>
&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;AdjustSize(int&nbsp;iNum)<br>
&nbsp;&nbsp;&nbsp;&nbsp;{<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(iNum&nbsp;&gt;&nbsp;0)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ThreadItem&nbsp;*pNew;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;EnterCriticalSection(&amp;_csThreadVector);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for(int&nbsp;_i=0;&nbsp;_i&lt;iNum;&nbsp;_i++)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_ThreadVector.push_back(pNew&nbsp;=&nbsp;new&nbsp;ThreadItem(this));<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;assert(pNew);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pNew-&gt;_Handle&nbsp;=&nbsp;CreateThread(NULL,&nbsp;0,&nbsp;DefaultJobProc,&nbsp;pNew,&nbsp;0,&nbsp;NULL);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;assert(pNew-&gt;_Handle);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LeaveCriticalSection(&amp;_csThreadVector);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;iNum&nbsp;*=&nbsp;-1;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ReleaseSemaphore(_SemaphoreDel,&nbsp;&nbsp;iNum&nbsp;&gt;&nbsp;_lThreadNum&nbsp;?&nbsp;_lThreadNum&nbsp;:&nbsp;iNum,&nbsp;NULL);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;(int)_lThreadNum;<br>
&nbsp;&nbsp;&nbsp;&nbsp;}<br>
&nbsp;&nbsp;&nbsp;&nbsp;//调用线程池<br>
&nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;Call(void&nbsp;(*pFunc)(void&nbsp;&nbsp;*),&nbsp;void&nbsp;*pPara&nbsp;=&nbsp;NULL)<br>
&nbsp;&nbsp;&nbsp;&nbsp;{<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;assert(pFunc);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;EnterCriticalSection(&amp;_csWorkQueue);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_JobQueue.push(new&nbsp;JobItem(pFunc,&nbsp;pPara));<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LeaveCriticalSection(&amp;_csWorkQueue);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ReleaseSemaphore(_SemaphoreCall,&nbsp;1,&nbsp;NULL);<br>
&nbsp;&nbsp;&nbsp;&nbsp;}<br>
&nbsp;&nbsp;&nbsp;&nbsp;//调用线程池<br>
&nbsp;&nbsp;&nbsp;&nbsp;inline&nbsp;void&nbsp;Call(ThreadJob&nbsp;*&nbsp;p,&nbsp;void&nbsp;*pPara&nbsp;=&nbsp;NULL)<br>
&nbsp;&nbsp;&nbsp;&nbsp;{<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Call(CallProc,&nbsp;new&nbsp;CallProcPara(p,&nbsp;pPara));<br>
&nbsp;&nbsp;&nbsp;&nbsp;}<br>
&nbsp;&nbsp;&nbsp;&nbsp;//结束线程池,&nbsp;并同步等待<br>
&nbsp;&nbsp;&nbsp;&nbsp;bool&nbsp;EndAndWait(DWORD&nbsp;dwWaitTime&nbsp;=&nbsp;INFINITE)<br>
&nbsp;&nbsp;&nbsp;&nbsp;{<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SetEvent(_EventEnd);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;WaitForSingleObject(_EventComplete,&nbsp;dwWaitTime)&nbsp;==&nbsp;WAIT_OBJECT_0;<br>
&nbsp;&nbsp;&nbsp;&nbsp;}<br>
&nbsp;&nbsp;&nbsp;&nbsp;//结束线程池<br>
&nbsp;&nbsp;&nbsp;&nbsp;inline&nbsp;void&nbsp;End()<br>
&nbsp;&nbsp;&nbsp;&nbsp;{<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SetEvent(_EventEnd);<br>
&nbsp;&nbsp;&nbsp;&nbsp;}<br>
&nbsp;&nbsp;&nbsp;&nbsp;inline&nbsp;DWORD&nbsp;Size()<br>
&nbsp;&nbsp;&nbsp;&nbsp;{<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;(DWORD)_lThreadNum;<br>
&nbsp;&nbsp;&nbsp;&nbsp;}<br>
&nbsp;&nbsp;&nbsp;&nbsp;inline&nbsp;DWORD&nbsp;GetRunningSize()<br>
&nbsp;&nbsp;&nbsp;&nbsp;{<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;(DWORD)_lRunningNum;<br>
&nbsp;&nbsp;&nbsp;&nbsp;}<br>
&nbsp;&nbsp;&nbsp;&nbsp;bool&nbsp;IsRunning()<br>
&nbsp;&nbsp;&nbsp;&nbsp;{<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;_lRunningNum&nbsp;&gt;&nbsp;0;<br>
&nbsp;&nbsp;&nbsp;&nbsp;}<br>
protected:<br>
&nbsp;&nbsp;&nbsp;&nbsp;//工作线程<br>
&nbsp;&nbsp;&nbsp;&nbsp;static&nbsp;DWORD&nbsp;WINAPI&nbsp;DefaultJobProc(LPVOID&nbsp;lpParameter&nbsp;=&nbsp;NULL)<br>
&nbsp;&nbsp;&nbsp;&nbsp;{<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ThreadItem&nbsp;*pThread&nbsp;=&nbsp;static_cast&lt;ThreadItem*&gt;(lpParameter);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;assert(pThread);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ThreadPool&nbsp;*pThreadPoolObj&nbsp;=&nbsp;pThread-&gt;_pThis;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;assert(pThreadPoolObj);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;InterlockedIncrement(&amp;pThreadPoolObj-&gt;_lThreadNum);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;HANDLE&nbsp;hWaitHandle[3];<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hWaitHandle[0]&nbsp;=&nbsp;pThreadPoolObj-&gt;_SemaphoreCall;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hWaitHandle[1]&nbsp;=&nbsp;pThreadPoolObj-&gt;_SemaphoreDel;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hWaitHandle[2]&nbsp;=&nbsp;pThreadPoolObj-&gt;_EventEnd;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;JobItem&nbsp;*pJob;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bool&nbsp;fHasJob;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for(;;)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;wr&nbsp;=&nbsp;WaitForMultipleObjects(3,&nbsp;hWaitHandle,&nbsp;false,&nbsp;INFINITE);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//响应删除线程信号<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(wr&nbsp;==&nbsp;WAIT_OBJECT_0&nbsp;+&nbsp;1)&nbsp;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//从队列里取得用户作业<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;EnterCriticalSection(&amp;pThreadPoolObj-&gt;_csWorkQueue);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(fHasJob&nbsp;=&nbsp;!pThreadPoolObj-&gt;_JobQueue.empty())<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pJob&nbsp;=&nbsp;pThreadPoolObj-&gt;_JobQueue.front();<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pThreadPoolObj-&gt;_JobQueue.pop();<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;assert(pJob);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LeaveCriticalSection(&amp;pThreadPoolObj-&gt;_csWorkQueue);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//受到结束线程信号确定是否结束线程(结束线程信号&amp;&amp;&nbsp;是否还有工作)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(wr&nbsp;==&nbsp;WAIT_OBJECT_0&nbsp;+&nbsp;2&nbsp;&amp;&amp;&nbsp;!fHasJob)&nbsp;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(fHasJob&nbsp;&amp;&amp;&nbsp;pJob)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;InterlockedIncrement(&amp;pThreadPoolObj-&gt;_lRunningNum);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pThread-&gt;_dwLastBeginTime&nbsp;=&nbsp;GetTickCount();<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pThread-&gt;_dwCount++;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pThread-&gt;_fIsRunning&nbsp;=&nbsp;true;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pJob-&gt;_pFunc(pJob-&gt;_pPara);&nbsp;//运行用户作业<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;delete&nbsp;pJob;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pThread-&gt;_fIsRunning&nbsp;=&nbsp;false;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;InterlockedDecrement(&amp;pThreadPoolObj-&gt;_lRunningNum);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//删除自身结构<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;EnterCriticalSection(&amp;pThreadPoolObj-&gt;_csThreadVector);<br>
&nbsp;&nbsp;&nbsp;&nbsp;pThreadPoolObj-&gt;_ThreadVector.erase(find(pThreadPoolObj-&gt;_ThreadVector.begin(),&nbsp;pThreadPoolObj-&gt;_ThreadVector.end(),&nbsp;pThread));<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LeaveCriticalSection(&amp;pThreadPoolObj-&gt;_csThreadVector);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;delete&nbsp;pThread;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;InterlockedDecrement(&amp;pThreadPoolObj-&gt;_lThreadNum);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(!pThreadPoolObj-&gt;_lThreadNum)&nbsp;&nbsp;//所有线程结束<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SetEvent(pThreadPoolObj-&gt;_EventComplete);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;0;<br>
&nbsp;&nbsp;&nbsp;&nbsp;}<br>
&nbsp;&nbsp;&nbsp;&nbsp;//调用用户对象虚函数<br>
&nbsp;&nbsp;&nbsp;&nbsp;static&nbsp;void&nbsp;CallProc(void&nbsp;*pPara)<br>
&nbsp;&nbsp;&nbsp;&nbsp;{<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CallProcPara&nbsp;*cp&nbsp;=&nbsp;static_cast&lt;CallProcPara&nbsp;*&gt;(pPara);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;assert(cp);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(cp)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cp-&gt;_pObj-&gt;DoJob(cp-&gt;_pPara);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;delete&nbsp;cp;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>
&nbsp;&nbsp;&nbsp;&nbsp;}<br>
&nbsp;&nbsp;&nbsp;&nbsp;//用户对象结构<br>
&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;CallProcPara&nbsp;<br>
&nbsp;&nbsp;&nbsp;&nbsp;{<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ThreadJob*&nbsp;_pObj;//用户对象<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;*_pPara;//用户参数<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CallProcPara(ThreadJob*&nbsp;p,&nbsp;void&nbsp;*pPara)&nbsp;:&nbsp;_pObj(p),&nbsp;_pPara(pPara)&nbsp;{&nbsp;};<br>
&nbsp;&nbsp;&nbsp;&nbsp;};<br>
&nbsp;&nbsp;&nbsp;&nbsp;//用户函数结构<br>
&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;JobItem<br>
&nbsp;&nbsp;&nbsp;&nbsp;{<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;(*_pFunc)(void&nbsp;&nbsp;*);//函数<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;*_pPara;&nbsp;//参数<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;JobItem(void&nbsp;(*pFunc)(void&nbsp;&nbsp;*)&nbsp;=&nbsp;NULL,&nbsp;void&nbsp;*pPara&nbsp;=&nbsp;NULL)&nbsp;:&nbsp;_pFunc(pFunc),&nbsp;_pPara(pPara)&nbsp;{&nbsp;};<br>
&nbsp;&nbsp;&nbsp;&nbsp;};<br>
&nbsp;&nbsp;&nbsp;&nbsp;//线程池中的线程结构<br>
&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;ThreadItem<br>
&nbsp;&nbsp;&nbsp;&nbsp;{<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;HANDLE&nbsp;_Handle;&nbsp;//线程句柄<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ThreadPool&nbsp;*_pThis;&nbsp;&nbsp;//线程池的指针<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;_dwLastBeginTime;&nbsp;//最后一次运行开始时间<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;_dwCount;&nbsp;//运行次数<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bool&nbsp;_fIsRunning;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ThreadItem(ThreadPool&nbsp;*pthis)&nbsp;:&nbsp;_pThis(pthis),&nbsp;_Handle(NULL),&nbsp;_dwLastBeginTime(0),&nbsp;_dwCount(0),&nbsp;_fIsRunning(false)&nbsp;{&nbsp;};<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;~ThreadItem()<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(_Handle)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CloseHandle(_Handle);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_Handle&nbsp;=&nbsp;NULL;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>
&nbsp;&nbsp;&nbsp;&nbsp;};<br>
&nbsp;&nbsp;&nbsp;&nbsp;std::queue&lt;JobItem&nbsp;*&gt;&nbsp;_JobQueue;&nbsp;&nbsp;//工作队列<br>
&nbsp;&nbsp;&nbsp;&nbsp;std::vector&lt;ThreadItem&nbsp;*&gt;&nbsp;&nbsp;_ThreadVector;&nbsp;//线程数据<br>
&nbsp;&nbsp;&nbsp;&nbsp;CRITICAL_SECTION&nbsp;_csThreadVector,&nbsp;_csWorkQueue;&nbsp;//工作队列临界,&nbsp;线程数据临界<br>
&nbsp;&nbsp;&nbsp;&nbsp;HANDLE&nbsp;_EventEnd,&nbsp;_EventComplete,&nbsp;_SemaphoreCall,&nbsp;_SemaphoreDel;//结束通知,&nbsp;完成事件,&nbsp;工作信号，删除线程信号<br>
&nbsp;&nbsp;&nbsp;&nbsp;long&nbsp;_lThreadNum,&nbsp;_lRunningNum;&nbsp;//线程数,&nbsp;运行的线程数<br>
};<br>
#endif&nbsp;//_ThreadPool_H_<br>
</div>
<p>使用说明1：</p>
<p align="left">调用方法</p>
<div class="cnblogs_code"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->void&nbsp;threadfunc(void&nbsp;*p)<br>
{<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;YourClass*&nbsp;yourObject&nbsp;=&nbsp;(YourClass*)&nbsp;&nbsp;&nbsp;&nbsp;p;<br>
&nbsp;//<img src="http://www.cnblogs.com/Images/dot.gif" alt=""><br>
}<br>
&nbsp;ThreadPool&nbsp;tp;<br>
&nbsp;for(i=0;&nbsp;i&lt;100;&nbsp;i++)<br>
&nbsp;&nbsp;tp.Call(threadfunc);<br>
ThreadPool&nbsp;tp(20);//20为初始线程池规模<br>
&nbsp;tp.Call(threadfunc,&nbsp;lpPara);<br>
</div>
<p align="left">使用时注意几点：</p>
<p align="left">1.&nbsp;ThreadJob &nbsp;没什么用，直接写线程函数吧。&nbsp;</p>
<p align="left">2. 线程函数（threadfunc）的入口参数void* 可以转成自定义的类型对象，这个对象可以记录下线程运行中的数据，并设置线程当前状态，以此与线程进行交互。</p>
<p align="left">3. 线程池有一个EndAndWait函数，用于让线程池中所有计算正常结束。有时线程池中的一个线程可能要运行很长时间，怎么办？可以通过线程函数threadfunc的入口参数对象来处理，比如：</p>
<div class="cnblogs_code"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->class&nbsp;YourClass&nbsp;<br>
{<br>
&nbsp;&nbsp;int&nbsp;cmd;&nbsp;//&nbsp;cmd&nbsp;=&nbsp;1是上线程停止计算，正常退出。<br>
};<br>
threadfunc(void*&nbsp;p)&nbsp;{<br>
&nbsp;&nbsp;YourClass*&nbsp;yourObject&nbsp;=&nbsp;(YourClass*)p;<br>
&nbsp;&nbsp;while&nbsp;(true)&nbsp;{<br>
&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;do&nbsp;some&nbsp;calculation<br>
&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(yourClass-&gt;cmd&nbsp;==&nbsp;1)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;<br>
&nbsp;&nbsp;}<br>
}<br>
</div>
<p align="left">在主线程中设置yourClass-&gt;cmd = 1，该线程就会自然结束。</p>
<p>使用说明2：</p>
<div class="cnblogs_code"><img id="Code_Closed_Image_114349" onclick="this.style.display='none'; document.getelementbyid('code_closed_text_114349').style.display="'none';" document.getelementbyid('code_open_image_114349').style.display="'inline';" document.getelementbyid('code_open_text_114349').style.display="'inline';"" src="http://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif" align="top" width="11" height="16"><img id="Code_Open_Image_114349" style="display: none;" onclick="this.style.display='none'; document.getelementbyid('code_open_text_114349').style.display="'none';" getelementbyid('code_closed_image_114349').style.display="'inline';" getelementbyid('code_closed_text_114349').style.display="'inline';"" src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align="top" width="11" height="16">Code<br>
<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->void&nbsp;threadfunc(void&nbsp;*p)<br>
{<br>
&nbsp;//<img src="http://www.cnblogs.com/Images/dot.gif" alt=""><br>
}<br>
&nbsp;ThreadPool&nbsp;tp;<br>
&nbsp;for(i=0;&nbsp;i&lt;100;&nbsp;i++)<br>
&nbsp;&nbsp;tp.Call(threadfunc);<br>
&nbsp;ThreadPool&nbsp;tp(20);//20为初始线程池规模<br>
&nbsp;tp.Call(threadfunc,&nbsp;lpPara);<br>
&nbsp;tp.AdjustSize(50);//增加50<br>
&nbsp;tp.AdjustSize(-30);//减少30<br>
</div>
<p>&nbsp;</p>
<div class="cnblogs_code"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->class&nbsp;MyThreadJob&nbsp;:&nbsp;public&nbsp;ThreadJob&nbsp;//线程对象从ThreadJob扩展<br>
{<br>
public:<br>
&nbsp;virtual&nbsp;void&nbsp;DoJob(void&nbsp;*p)//自定义的虚函数<br>
&nbsp;{<br>
&nbsp;&nbsp;//<img src="http://www.cnblogs.com/Images/dot.gif" alt="">.<br>
&nbsp;}<br>
};<br>
&nbsp;MyThreadJob&nbsp;mt[10];<br>
&nbsp;ThreadPool&nbsp;tp;<br>
&nbsp;for(i=0;&nbsp;i&lt;100&nbsp;i++)<br>
&nbsp;&nbsp;tp.Call(mt&nbsp;+&nbsp;i);//tp.Call(mt&nbsp;+&nbsp;i,&nbsp;para);<br>
</div>
<br><img src ="http://www.cppblog.com/michaelgao/aggbug/72810.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/michaelgao/" target="_blank">micheal's tech</a> 2009-02-02 16:28 <a href="http://www.cppblog.com/michaelgao/archive/2009/02/02/72810.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>多线程同步机制摘要</title><link>http://www.cppblog.com/michaelgao/archive/2009/02/02/72805.html</link><dc:creator>micheal's tech</dc:creator><author>micheal's tech</author><pubDate>Mon, 02 Feb 2009 06:35:00 GMT</pubDate><guid>http://www.cppblog.com/michaelgao/archive/2009/02/02/72805.html</guid><wfw:comment>http://www.cppblog.com/michaelgao/comments/72805.html</wfw:comment><comments>http://www.cppblog.com/michaelgao/archive/2009/02/02/72805.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/michaelgao/comments/commentRss/72805.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/michaelgao/services/trackbacks/72805.html</trackback:ping><description><![CDATA[<div class="posthead">
<h2>
<a id="viewpost1_TitleUrl" class="singleposttitle" href="http://www.cppblog.com/jacky2019/archive/2007/04/03/21190.html">多线程同步机制摘要</a>
</h2>
Posted on 2007-04-03 19:34 <a href="http://www.cppblog.com/jacky2019/">kk</a> 阅读(1306) <a href="http://www.cppblog.com/jacky2019/archive/2007/04/03/21190.html#Post">评论(0)</a> &nbsp;<a href="http://www.cppblog.com/jacky2019/admin/EditPosts.aspx?postid=21190">编辑</a>&nbsp;<a href="http://www.cppblog.com/jacky2019/AddToFavorite.aspx?id=21190">收藏</a> <a href="http://www.cppblog.com/jacky2019/services/trackbacks/21190.aspx">引用</a>  所属分类: <a href="http://www.cppblog.com/jacky2019/category/3694.html">IT</a>
<img src="http://www.cppblog.com/jacky2019/aggbug/21190.html?webview=1" width="1" height="1">
<!--
-->
</div>
&nbsp;<strong> Critical Section</strong>
<p>Critical section（临界区）用来实现&#8220;排他性占有&#8221;。适用范围是单一进程的各线程之间。它是：</p>
<p>&#183;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 一个局部性对象，不是一个核心对象。</p>
<p>&#183;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 快速而有效率。</p>
<p>&#183;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 不能够同时有一个以上的critical section被等待。</p>
<p>&#183;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 无法侦测是否已被某个线程放弃。</p>
<p><strong> Mutex</strong> </p>
<p>Mutex是一个核心对象，可以在不同的线程之间实现&#8220;排他性占有&#8221;，甚至几十那些现成分属不同进程。它是：</p>
<p>&#183;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 一个核心对象。</p>
<p>&#183;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 如果拥有mutex的那个线程结束，则会产生一个&#8220;abandoned&#8221;错误信息。</p>
<p>&#183;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 可以使用Wait&#8230;()等待一个mutex。</p>
<p>&#183;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 可以具名，因此可以被其他进程开启。</p>
<p>&#183;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 只能被拥有它的那个线程释放（released）。</p>
<p><strong> Semaphore</strong> </p>
<p>Semaphore被用来追踪有限的资源。它是：</p>
<p>&#183;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 一个核心对象。</p>
<p>&#183;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 没有拥有者。</p>
<p>&#183;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 可以具名，因此可以被其他进程开启。</p>
<p>&#183;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 可以被任何一个线程释放（released）。</p>
<p><strong> Event Object</strong> </p>
<p>Event object通常使用于overlapped I/O，或用来设计某些自定义的同步对象。它是：</p>
<p>&#183;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 一个核心对象。</p>
<p>&#183;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 完全在程序掌控之下。</p>
<p>&#183;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 适用于设计新的同步对象。</p>
<p>&#183;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#8220;要求苏醒&#8221;的请求并不会被储存起来，可能会遗失掉。</p>
<p>&#183;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 可以具名，因此可以被其他进程开启。</p>
<p><strong> Interlocked Variable</strong> </p>
<p>如果Interlocked&#8230;()函数被使用于所谓的spin-lock，那么他们只是一种同步机制。所谓spin-lock是一种busy loop，被预期在极短时间内执行，所以有最小的额外负担（overhead）。系统核心偶尔会使用他们。除此之外，interlocked variables主要用于引用技术。他们：</p>
<p>&#183;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 允许对4字节的数值有些基本的同步操作，不需动用到critical section或mutex之类。</p>
<p>&#183;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在SMP（Symmetric Multi-Processors）操作系统中亦可有效运作。</p>
<br><img src ="http://www.cppblog.com/michaelgao/aggbug/72805.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/michaelgao/" target="_blank">micheal's tech</a> 2009-02-02 14:35 <a href="http://www.cppblog.com/michaelgao/archive/2009/02/02/72805.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>placement new释疑</title><link>http://www.cppblog.com/michaelgao/archive/2009/01/08/71527.html</link><dc:creator>micheal's tech</dc:creator><author>micheal's tech</author><pubDate>Thu, 08 Jan 2009 12:56:00 GMT</pubDate><guid>http://www.cppblog.com/michaelgao/archive/2009/01/08/71527.html</guid><wfw:comment>http://www.cppblog.com/michaelgao/comments/71527.html</wfw:comment><comments>http://www.cppblog.com/michaelgao/archive/2009/01/08/71527.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/michaelgao/comments/commentRss/71527.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/michaelgao/services/trackbacks/71527.html</trackback:ping><description><![CDATA[<br>
<p>"placement new"? <img alt="Embarrassed" src="http://messenger.msn.com/MMM2006-04-19_17.00/Resource/emoticons/red_smile.gif">它
到底是什么东东呀？我也是最近几天才听说，看来对于C++我还差很远呀！placement new 是重载operator
new的一个标准、全局的版本，它不能被自定义的版本代替（不像普通的operator new和operator
delete能够被替换成用户自定义的版本）。</p>
<p>它的原型如下：   <br>void *operator new( size_t, void *p ) throw()&nbsp; { return p; }</p>
<p>首先我们区分下几个容易混淆的关键词：new、operator new、placement new   <br>new和delete操作符我们应该都用过，它们是对<a href="http://www.ksarea.com/articles/20070829_memory-partition-stack-heap-difference.html" target="_blank">堆</a>中的内存进行申请和释放，而这两个都是不能被重载的。要实现不同的内存分配行为，需要重载operator new，而不是new和delete。<img alt="I dont know" src="http://us.i1.yimg.com/us.yimg.com/i/mesg/emoticons7/106.gif"></p>
<p>看如下代码：   <br>class MyClass {&#8230;};    <br>MyClass * p=new MyClass;</p>
<p>这里的new实际上是执行如下3个过程：</p>
<p><br>
1. 调用operator new分配内存 ；2. 调用构造函数生成类对象；3. 返回相应指针。
</p>
<p>operator new就像operator+一样，是可以重载的，但是不能在全局对原型为void operator new(size_t
size)这个原型进行重载，一般只能在类中进行重载。如果类中没有重载operator new，那么调用的就是全局的::operator
new来完成堆的分配。同理，operator new[]、operator delete、operator
delete[]也是可以重载的，一般你重载的其中一个，那么最后把其余的三个都重载一遍。</p>
<p>至于placement new才是本文的重点。其实它也只是operator
new的一个重载的版本，只是我们很少用到它。如果你想在已经分配的内存中创建一个对象，使用new时行不通的。也就是说placement
new允许你在一个已经分配好的内存中（栈或者堆中）构造一个新的对象。原型中void*p实际上就是指向一个已经分配好的内存缓冲区的的首地址。</p>
<p>我们知道使用new操作符分配内存需要在堆中查找足够大的剩余空间，这个操作速度是很慢的，而且有可能出现无法分配内存的异常（空间不够）。
placement
new就可以解决这个问题。我们构造对象都是在一个预先准备好了的内存缓冲区中进行，不需要查找内存，内存分配的时间是常数；而且不会出现在程序运行中途
出现内存不足的异常。所以，placement new非常适合那些对时间要求比较高，长时间运行不希望被打断的应用程序。</p>
<p>使用方法如下：   <br>1. 缓冲区提前分配    <br>可以使用堆的空间，也可以使用栈的空间，所以分配方式有如下两种：    <br>class MyClass {&#8230;};    <br>char *buf=new char[N*sizeof(MyClass)+<strong> sizeof(int)</strong> ]<strong> ;</strong> 或者char buf[N*sizeof(MyClass)+<strong> sizeof(int)</strong> ];</p>
<p>2. 对象的构造   <br>MyClass * pClass=new(buf) MyClass;</p>
<p>3. 对象的销毁   <br>一旦这个对象使用完毕，<font color="#ff0000">你必须显式的调用类的析构函数进行销毁对象</font>。但此时内存空间不会被释放，以便其他的对象的构造。    <br>pClass-&gt;~MyClass();</p>
<p>4. 内存的释放   <br>如果缓冲区在堆中，那么调用delete[] buf;进行内存的释放；如果在栈中，那么在其作用域内有效，跳出作用域，内存自动释放。</p>
<p>注意：</p>
<ul>
    <li>在C++标准中，对于placement operator new []有如下的说明： placement operator new[]
    needs implementation-defined amount of additional storage to save a
    size of array. 所以我们必须申请比原始对象大小多出sizeof(int)个字节来存放对象的个数，或者说数组的大小。 </li>
    <li>使用方法第二步中的new才是placement new，其实是没有申请内存的，只是调用了构造函数，返回一个指向已经分配好的内存的一个指针，所以对象销毁的时候不需要调用delete释放空间，但必须调用析构函数销毁对象。 </li>
</ul>
<br> <img src ="http://www.cppblog.com/michaelgao/aggbug/71527.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/michaelgao/" target="_blank">micheal's tech</a> 2009-01-08 20:56 <a href="http://www.cppblog.com/michaelgao/archive/2009/01/08/71527.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>内存池</title><link>http://www.cppblog.com/michaelgao/archive/2008/11/17/67122.html</link><dc:creator>micheal's tech</dc:creator><author>micheal's tech</author><pubDate>Mon, 17 Nov 2008 08:37:00 GMT</pubDate><guid>http://www.cppblog.com/michaelgao/archive/2008/11/17/67122.html</guid><wfw:comment>http://www.cppblog.com/michaelgao/comments/67122.html</wfw:comment><comments>http://www.cppblog.com/michaelgao/archive/2008/11/17/67122.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/michaelgao/comments/commentRss/67122.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/michaelgao/services/trackbacks/67122.html</trackback:ping><description><![CDATA[http://www.ibm.com/developerworks/cn/linux/l-cn-ppp/index6.html?ca=drs-cn
<br><blockquote>本章首先简单介绍自定义内存池性能优化的原理，然后列举软件开发中常用的内存池的不同类型，并给出具体实现的实例。</blockquote><!--start RESERVED FOR FUTURE USE INCLUDE FILES--><!-- include java script once we verify teams wants to use this and it will work on dbcs and cyrillic characters -->
<!--end RESERVED FOR FUTURE USE INCLUDE FILES-->
<p><a name="N10086">引言</a></p>
<p>本
书主要针对的是 C++ 程序的性能优化，深入介绍 C++ 程序性能优化的方法和实例。全书由 4 个篇组成，第 1 篇介绍 C++
语言的对象模型，该篇是优化 C++ 程序的基础；第 2 篇主要针对如何优化 C++ 程序的内存使用；第 3 篇介绍如何优化程序的启动性能；第
4 篇介绍了三类性能优化工具，即内存分析工具、性能分析工具和 I/O 检测工具，它们是测量程序性能的利器。</p>
<p>在此我们推出了此书的第 <a href="http://www.ibm.com/developerworks/cn/linux/l-cn-ppp/index2.html">2</a>、<a href="http://www.ibm.com/developerworks/cn/linux/l-cn-ppp/index6.html">6</a> 章供大家在线浏览。更多推荐书籍请访问 <a href="http://www.ibm.com/developerworks/cn/books/index.html">developerWorks 图书频道</a>。
</p>
<br>
<table width="100%" border="0" cellpadding="0" cellspacing="0">
    <tbody>
        <tr>
            <td><img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" width="100%" height="1"><br><img alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" height="6"></td>
        </tr>
    </tbody>
</table>
<table class="no-print" align="right" cellpadding="0" cellspacing="0">
    <tbody>
        <tr align="right">
            <td><img src="http://www.ibm.com/i/c.gif" alt="" width="100%" height="4"><br>
            <table border="0" cellpadding="0" cellspacing="0">
                <tbody>
                    <tr>
                        <td valign="middle"><img src="http://www.ibm.com/i/v14/icons/u_bold.gif" alt="" width="16" border="0" height="16"><br></td>
                        <td valign="top" align="right"><a href="http://www.ibm.com/developerworks/cn/linux/l-cn-ppp/index6.html?ca=drs-cn#main" class="fbox"><strong>回页首</strong></a></td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
<br><br>
<p><a name="N1009E">6.1  自定义内存池性能优化的原理</a></p>
<table width="40%" align="right" border="0" cellpadding="0" cellspacing="0">
    <tbody>
        <tr>
            <td width="10"><img alt="" src="http://www.ibm.com/i/c.gif" width="10" height="1"></td>
            <td>
            <table width="100%" border="1" cellpadding="5" cellspacing="0">
                <tbody>
                    <tr>
                        <td bgcolor="#eeeeee">
                        <p>
                        </p>
                        <table width="100%" border="0" cellpadding="0" cellspacing="0">
                            <tbody>
                                <tr>
                                    <td valign="top">
                                    <br>
                                    </td>
                                    <td valign="top">
                                    <img alt="" src="http://www.ibm.com/i/c.gif" width="10" border="0">
                                    </td>
                                    <td>                                <strong>书名：</strong>《C++应用程序性能优化》
                                    <br>
                                    <strong>作者：</strong>冯宏华、徐莹、程远、汪磊 等编著
                                    <br>
                                    <strong>出版社：</strong>电子工业出版社
                                    <br>
                                    <strong>出版日期：</strong>2007 年 03 月
                                    <br>
                                    <strong>ISBN：</strong>978-7-121-03831-0
                                    <br>
                                    <strong>购买：</strong>
                                    <a href="http://www.china-pub.com/computers/common/info.asp?id=34206">中国互动出版网</a>	、<a href="http://www.dearbook.com.cn/book/129969">dearbook</a>
                                    </td>
                                </tr>
                                <tr>
                                    <td colspan="3">
                                    <p>
                                    <strong>推荐章节:</strong>
                                    </p>
                                    <ul>
                                        <li>
                                        <a href="http://www.ibm.com/developerworks/cn/books/more.html">前言和目录</a>
                                        </li>
                                        <li>
                                        <a href="http://www.ibm.com/developerworks/cn/linux/l-cn-ppp/index2.html">第 2 章：C++ 语言特性的性能分析</a>
                                        </li>
                                        <li>
                                        <a href="http://www.ibm.com/developerworks/cn/linux/l-cn-ppp/index6.html">第 6 章：内存池</a>
                                        </li>
                                    </ul>
                                    <p>
                                    <br></p>
                                    </td>
                                </tr>
                            </tbody>
                        </table>
                        </td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
<p>如
前所述，读者已经了解到"堆"和"栈"的区别。而在编程实践中，不可避免地要大量用到堆上的内存。例如在程序中维护一个链表的数据结构时，每次新增或者删
除一个链表的节点，都需要从内存堆上分配或者释放一定的内存；在维护一个动态数组时，如果动态数组的大小不能满足程序需要时，也要在内存堆上分配新的内存
空间。</p>
<p><a name="N10126">6.1.1  默认内存管理函数的不足</a></p>
<p>利用默认的内存管理函数new/delete或malloc/free在堆上分配和释放内存会有一些额外的开销。</p>
<p>系
统在接收到分配一定大小内存的请求时，首先查找内部维护的内存空闲块表，并且需要根据一定的算法（例如分配最先找到的不小于申请大小的内存块给请求者，或
者分配最适于申请大小的内存块，或者分配最大空闲的内存块等）找到合适大小的空闲内存块。如果该空闲内存块过大，还需要切割成已分配的部分和较小的空闲
块。然后系统更新内存空闲块表，完成一次内存分配。类似地，在释放内存时，系统把释放的内存块重新加入到空闲内存块表中。如果有可能的话，可以把相邻的空
闲块合并成较大的空闲块。</p>
<p>默认的内存管理函数还考虑到多线程的应用，需要在每次分配和释放内存时加锁，同样增加了开销。</p>
<p>可见，如果应用程序频繁地在堆上分配和释放内存，则会导致性能的损失。并且会使系统中出现大量的内存碎片，降低内存的利用率。</p>
<p>默认的分配和释放内存算法自然也考虑了性能，然而这些内存管理算法的通用版本为了应付更复杂、更广泛的情况，需要做更多的额外工作。而对于某一个具体的应用程序来说，适合自身特定的内存分配释放模式的自定义内存池则可以获得更好的性能。</p>
<p><a name="N1013B">6.1.2  内存池的定义和分类</a></p>
<p>自
定义内存池的思想通过这个"池"字表露无疑，应用程序可以通过系统的内存分配调用预先一次性申请适当大小的内存作为一个内存池，之后应用程序自己对内存的
分配和释放则可以通过这个内存池来完成。只有当内存池大小需要动态扩展时，才需要再调用系统的内存分配函数，其他时间对内存的一切操作都在应用程序的掌控
之中。</p>
<p>应用程序自定义的内存池根据不同的适用场景又有不同的类型。</p>
<p>从
线程安全的角度来分，内存池可以分为单线程内存池和多线程内存池。单线程内存池整个生命周期只被一个线程使用，因而不需要考虑互斥访问的问题；多线程内存
池有可能被多个线程共享，因此则需要在每次分配和释放内存时加锁。相对而言，单线程内存池性能更高，而多线程内存池适用范围更广。</p>
<p>从内存池可分配内存单元大小来分，可以分为固定内存池和可变内存池。所谓固定内存池是指应用程序每次从内存池中分配出来的内存单元大小事先已经确定，是固定不变的；而可变内存池则每次分配的内存单元大小可以按需变化，应用范围更广，而性能比固定内存池要低。</p>
<p><a name="N1014D">6.1.3  内存池工作原理示例</a></p>
<p>下面以固定内存池为例说明内存池的工作原理，如图6-1所示。</p>
<br><a name="N10158"><strong>图6-1  固定内存池</strong></a><br>
<img alt="图6-1  固定内存池" src="http://www.ibm.com/developerworks/cn/linux/l-cn-ppp/images6/6_1.gif" width="498" border="0" height="211">
<br>
<p>固定内存池由一系列固定大小的内存块组成，每一个内存块又包含了固定数量和大小的内存单元。</p>
<p>如
图6-1所示，该内存池一共包含4个内存块。在内存池初次生成时，只向系统申请了一个内存块，返回的指针作为整个内存池的头指针。之后随着应用程序对内存
的不断需求，内存池判断需要动态扩大时，才再次向系统申请新的内存块，并把所有这些内存块通过指针链接起来。对于操作系统来说，它已经为该应用程序分配了
4个等大小的内存块。由于是大小固定的，所以分配的速度比较快；而对于应用程序来说，其内存池开辟了一定大小，内存池内部却还有剩余的空间。</p>
<p>例
如放大来看第4个内存块，其中包含一部分内存池块头信息和3个大小相等的内存池单元。单元1和单元3是空闲的，单元2已经分配。当应用程序需要通过该内存
池分配一个单元大小的内存时，只需要简单遍历所有的内存池块头信息，快速定位到还有空闲单元的那个内存池块。然后根据该块的块头信息直接定位到第1个空闲
的单元地址，把这个地址返回，并且标记下一个空闲单元即可；当应用程序释放某一个内存池单元时，直接在对应的内存池块头信息中标记该内存单元为空闲单元即
可。</p>
<p>可见与系统管理内存相比，内存池的操作非常迅速，它在性能优化方面的优点主要如下。</p>
<p>（1）针对特殊情况，例如需要频繁分配释放固定大小的内存对象时，不需要复杂的分配算法和多线程保护。也不需要维护内存空闲表的额外开销，从而获得较高的性能。</p>
<p>（2）由于开辟一定数量的连续内存空间作为内存池块，因而一定程度上提高了程序局部性，提升了程序性能。</p>
<p>（3）比较容易控制页边界对齐和内存字节对齐，没有内存碎片的问题。</p>
<br>
<table width="100%" border="0" cellpadding="0" cellspacing="0">
    <tbody>
        <tr>
            <td><img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" width="100%" height="1"><br><img alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" height="6"></td>
        </tr>
    </tbody>
</table>
<table class="no-print" align="right" cellpadding="0" cellspacing="0">
    <tbody>
        <tr align="right">
            <td><img src="http://www.ibm.com/i/c.gif" alt="" width="100%" height="4"><br>
            <table border="0" cellpadding="0" cellspacing="0">
                <tbody>
                    <tr>
                        <td valign="middle"><img src="http://www.ibm.com/i/v14/icons/u_bold.gif" alt="" width="16" border="0" height="16"><br></td>
                        <td valign="top" align="right"><a href="http://www.ibm.com/developerworks/cn/linux/l-cn-ppp/index6.html?ca=drs-cn#main" class="fbox"><strong>回页首</strong></a></td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
<br><br>
<p><a name="N1017D">6.2  一个内存池的实现实例</a></p>
<p>本节分析在某个大型应用程序实际应用到的一个内存池实现，并详细讲解其使用方法与工作原理。这是一个应用于单线程环境且分配单元大小固定的内存池，一般用来为执行时会动态频繁地创建且可能会被多次创建的类对象或者结构体分配内存。</p>
<p>本节首先讲解该内存池的数据结构声明及图示，接着描述其原理及行为特征。然后逐一讲解实现细节，最后介绍如何在实际程序中应用此内存池，并与使用普通内存函数申请内存的程序性能作比较。</p>
<p><a name="N10189">6.2.1  内部构造</a></p>
<p>内存池类MemoryPool的声明如下：</p>
<br>
<table width="100%" border="0" cellpadding="0" cellspacing="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">class MemoryPool<br>{<br>private:<br>    MemoryBlock*   pBlock;<br>    USHORT          nUnitSize;<br>    USHORT          nInitSize;<br>    USHORT          nGrowSize;<br><br>public:<br>                     MemoryPool( USHORT nUnitSize,<br>                                  USHORT nInitSize = 1024,<br>                                  USHORT nGrowSize = 256 );<br>                    ~MemoryPool();<br><br>    void*           Alloc();<br>    void            Free( void* p );<br>};<br></pre>
            </td>
        </tr>
    </tbody>
</table>
<br>
<p>MemoryBlock为内存池中附着在真正用来为内存请求分配内存的内存块头部的结构体，它描述了与之联系的内存块的使用信息：</p>
<br>
<table width="100%" border="0" cellpadding="0" cellspacing="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">struct MemoryBlock<br>{<br>    USHORT          nSize;<br>    USHORT          nFree;<br>    USHORT          nFirst;<br>    USHORT          nDummyAlign1;<br>    MemoryBlock*  pNext;<br>    char            aData[1];<br><br>	static void* operator new(size_t, USHORT nTypes, USHORT nUnitSize)<br>	{<br>		return ::operator new(sizeof(MemoryBlock) + nTypes * nUnitSize);<br>	}<br>	static void  operator delete(void *p, size_t)<br>	{<br>		::operator delete (p);<br>	}<br><br>	MemoryBlock (USHORT nTypes = 1, USHORT nUnitSize = 0);<br>	~MemoryBlock() {}<br>};<br></pre>
            </td>
        </tr>
    </tbody>
</table>
<br>
<p>此内存池的数据结构如图6-2所示。</p>
<br><a name="N101AC"><strong>图6-2  内存池的数据结构</strong></a><br>
<img alt="图6-2  内存池的数据结构" src="http://www.ibm.com/developerworks/cn/linux/l-cn-ppp/images6/6_2.gif" width="544" border="0" height="369">
<br>
<p><a name="N101BC">6.2.2  总体机制</a></p>
<p>此内存池的总体机制如下。</p>
<p>（1）
在运行过程中，MemoryPool内存池可能会有多个用来满足内存申请请求的内存块，这些内存块是从进程堆中开辟的一个较大的连续内存区域，它由一个
MemoryBlock结构体和多个可供分配的内存单元组成，所有内存块组成了一个内存块链表，MemoryPool的pBlock是这个链表的头。对每
个内存块，都可以通过其头部的MemoryBlock结构体的pNext成员访问紧跟在其后面的那个内存块。</p>
<p>（2）
每个内存块由两部分组成，即一个MemoryBlock结构体和多个内存分配单元。这些内存分配单元大小固定（由MemoryPool的
nUnitSize表示），MemoryBlock结构体并不维护那些已经分配的单元的信息；相反，它只维护没有分配的自由分配单元的信息。它有两个成员
比较重要：nFree和nFirst。nFree记录这个内存块中还有多少个自由分配单元，而nFirst则记录下一个可供分配的单元的编号。每一个自由
分配单元的头两个字节（即一个USHORT型值）记录了紧跟它之后的下一个自由分配单元的编号，这样，通过利用每个自由分配单元的头两个字节，一个
MemoryBlock中的所有自由分配单元被链接起来。</p>
<p>（3）当有新的内存请求到来
时，MemoryPool会通过pBlock遍历MemoryBlock链表，直到找到某个MemoryBlock所在的内存块，其中还有自由分配单元
（通过检测MemoryBlock结构体的nFree成员是否大于0）。如果找到这样的内存块，取得其MemoryBlock的nFirst值（此为该内
存块中第1个可供分配的自由单元的编号）。然后根据这个编号定位到该自由分配单元的起始位置（因为所有分配单元大小固定，因此每个分配单元的起始位置都可
以通过编号分配单元大小来偏移定位），这个位置就是用来满足此次内存申请请求的内存的起始地址。但在返回这个地址前，需要首先将该位置开始的头两个字节的
值（这两个字节值记录其之后的下一个自由分配单元的编号）赋给本内存块的MemoryBlock的nFirst成员。这样下一次的请求就会用这个编号对应
的内存单元来满足，同时将此内存块的MemoryBlock的nFree递减1，然后才将刚才定位到的内存单元的起始位置作为此次内存请求的返回地址返回
给调用者。</p>
<p>（4）如果从现有的内存块中找不到一个自由的内存分配单元（当第1次请求内存，以及现有的所有内存
块中的所有内存分配单元都已经被分配时会发生这种情形），MemoryPool就会从进程堆中申请一个内存块（这个内存块包括一个MemoryBlock
结构体，及紧邻其后的多个内存分配单元，假设内存分配单元的个数为n，n可以取值MemoryPool中的nInitSize或者nGrowSize），
申请完后，并不会立刻将其中的一个分配单元分配出去，而是需要首先初始化这个内存块。初始化的操作包括设置MemoryBlock的nSize为所有内存
分配单元的大小（注意，并不包括MemoryBlock结构体的大小）、nFree为n-1（注意，这里是n-1而不是n，因为此次新内存块就是为了满足
一次新的内存请求而申请的，马上就会分配一块自由存储单元出去，如果设为n-1，分配一个自由存储单元后无须再将n递减1），nFirst为1（已经知道
nFirst为下一个可以分配的自由存储单元的编号。为1的原因与nFree为n-1相同，即立即会将编号为0的自由分配单元分配出去。现在设为1，其后
不用修改nFirst的值），MemoryBlock的构造需要做更重要的事情，即将编号为0的分配单元之后的所有自由分配单元链接起来。如前所述，每个
自由分配单元的头两个字节用来存储下一个自由分配单元的编号。另外，因为每个分配单元大小固定，所以可以通过其编号和单元大小（MemoryPool的
nUnitSize成员）的乘积作为偏移值进行定位。现在唯一的问题是定位从哪个地址开始？答案是MemoryBlock的aData[1]成员开始。因
为aData[1]实际上是属于MemoryBlock结构体的（MemoryBlock结构体的最后一个字节），所以实质上，MemoryBlock结
构体的最后一个字节也用做被分配出去的分配单元的一部分。因为整个内存块由MemoryBlock结构体和整数个分配单元组成，这意味着内存块的最后一个
字节会被浪费，这个字节在图6-2中用位于两个内存的最后部分的浓黑背景的小块标识。确定了分配单元的起始位置后，将自由分配单元链接起来的工作就很容易
了。即从aData位置开始，每隔nUnitSize大小取其头两个字节，记录其之后的自由分配单元的编号。因为刚开始所有分配单元都是自由的，所以这个
编号就是自身编号加1，即位置上紧跟其后的单元的编号。初始化后，将此内存块的第1个分配单元的起始地址返回，已经知道这个地址就是aData。</p>
<p>（5）
当某个被分配的单元因为delete需要回收时，该单元并不会返回给进程堆，而是返回给MemoryPool。返回时，MemoryPool能够知道该单
元的起始地址。这时，MemoryPool开始遍历其所维护的内存块链表，判断该单元的起始地址是否落在某个内存块的地址范围内。如果不在所有内存地址范
围内，则这个被回收的单元不属于这个MemoryPool；如果在某个内存块的地址范围内，那么它会将这个刚刚回收的分配单元加到这个内存块的
MemoryBlock所维护的自由分配单元链表的头部，同时将其nFree值递增1。回收后，考虑到资源的有效利用及后续操作的性能，内存池的操作会继
续判断：如果此内存块的所有分配单元都是自由的，那么这个内存块就会从MemoryPool中被移出并作为一个整体返回给进程堆；如果该内存块中还有非自
由分配单元，这时不能将此内存块返回给进程堆。但是因为刚刚有一个分配单元返回给了这个内存块，即这个内存块有自由分配单元可供下次分配，因此它会被移到
MemoryPool维护的内存块的头部。这样下次的内存请求到来，MemoryPool遍历其内存块链表以寻找自由分配单元时，第1次寻找就会找到这个
内存块。因为这个内存块确实有自由分配单元，这样可以减少MemoryPool的遍历次数。</p>
<p>综上所述，每个内
存池（MemoryPool）维护一个内存块链表（单链表），每个内存块由一个维护该内存块信息的块头结构（MemoryBlock）和多个分配单元组
成，块头结构MemoryBlock则进一步维护一个该内存块的所有自由分配单元组成的"链表"。这个链表不是通过"指向下一个自由分配单元的指针"链接
起来的，而是通过"下一个自由分配单元的编号"链接起来，这个编号值存储在该自由分配单元的头两个字节中。另外，第1个自由分配单元的起始位置并不是
MemoryBlock结构体"后面的"第1个地址位置，而是MemoryBlock结构体"内部"的最后一个字节aData（也可能不是最后一个，因为
考虑到字节对齐的问题），即分配单元实际上往前面错了一位。又因为MemoryBlock结构体后面的空间刚好是分配单元的整数倍，这样依次错位下去，内
存块的最后一个字节实际没有被利用。这么做的一个原因也是考虑到不同平台的移植问题，因为不同平台的对齐方式可能不尽相同。即当申请
MemoryBlock大小内存时，可能会返回比其所有成员大小总和还要大一些的内存。最后的几个字节是为了"补齐"，而使得aData成为第1个分配单
元的起始位置，这样在对齐方式不同的各种平台上都可以工作。</p>
<p><a name="N101D7">6.2.3  细节剖析</a></p>
<p>有了上述的总体印象后，本节来仔细剖析其实现细节。</p>
<p>（1）MemoryPool的构造如下：</p>
<br>
<table width="100%" border="0" cellpadding="0" cellspacing="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">MemoryPool::MemoryPool( USHORT _nUnitSize,<br>                            USHORT _nInitSize, USHORT _nGrowSize )<br>{<br>    pBlock      = NULL;	            ①<br>    nInitSize   = _nInitSize;       ②<br>    nGrowSize   = _nGrowSize;       ③<br><br>    if ( _nUnitSize &gt; 4 )<br>        nUnitSize = (_nUnitSize + (MEMPOOL_ALIGNMENT-1)) &amp; ~(MEMPOOL_ALIGNMENT-1); ④<br>    else if ( _nUnitSize &lt;= 2 )<br>        nUnitSize = 2;              ⑤<br>    else<br>        nUnitSize = 4;<br>}<br></pre>
            </td>
        </tr>
    </tbody>
</table>
<br>
<p>从①处可以看出，MemoryPool创建时，并没有立刻创建真正用来满足内存申请的内存块，即内存块链表刚开始时为空。</p>
<p>②处和③处分别设置"第1次创建的内存块所包含的分配单元的个数"，及"随后创建的内存块所包含的分配单元的个数"，这两个值在MemoryPool创建时通过参数指定，其后在该MemoryPool对象生命周期中一直不变。</p>
<p>后
面的代码用来设置nUnitSize，这个值参考传入的_nUnitSize参数。但是还需要考虑两个因素。如前所述，每个分配单元在自由状态时，其头两
个字节用来存放"其下一个自由分配单元的编号"。即每个分配单元"最少"有"两个字节"，这就是⑤处赋值的原因。④处是将大于4个字节的大小
_nUnitSize往上"取整到"大于_nUnitSize的最小的MEMPOOL_
ALIGNMENT的倍数（前提是MEMPOOL_ALIGNMENT为2的倍数）。如_nUnitSize为11
时，MEMPOOL_ALIGNMENT为8，nUnitSize为16；MEMPOOL_ALIGNMENT为4，nUnitSize为
12；MEMPOOL_ALIGNMENT为2，nUnitSize为12，依次类推。</p>
<p>（2）当向MemoryPool提出内存请求时：</p>
<br>
<table width="100%" border="0" cellpadding="0" cellspacing="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">void* MemoryPool::Alloc()<br>{<br>    if ( !pBlock )           ①<br>    {<br>			&#8230;&#8230;							<br>    }<br><br>    MemoryBlock* pMyBlock = pBlock;<br>    while (pMyBlock &amp;&amp; !pMyBlock-&gt;nFree )②<br>        pMyBlock = pMyBlock-&gt;pNext;<br><br>    if ( pMyBlock )	         ③<br>    {<br>        char* pFree = pMyBlock-&gt;aData+(pMyBlock-&gt;nFirst*nUnitSize);			<br>        pMyBlock-&gt;nFirst = *((USHORT*)pFree);<br>							<br>        pMyBlock-&gt;nFree--;	<br>        return (void*)pFree;<br>    }<br>    else                    ④<br>    {<br>        if ( !nGrowSize )<br>            return NULL;<br><br>		pMyBlock = new(nGrowSize, nUnitSize) FixedMemBlock(nGrowSize, nUnitSize);<br>        if ( !pMyBlock )<br>            return NULL;<br><br>        pMyBlock-&gt;pNext = pBlock;<br>        pBlock = pMyBlock;<br><br>        return (void*)(pMyBlock-&gt;aData);<br>    }<br><br>}<br></pre>
            </td>
        </tr>
    </tbody>
</table>
<br>
<p>MemoryPool满足内存请求的步骤主要由四步组成。</p>
<p>①
处首先判断内存池当前内存块链表是否为空，如果为空，则意味着这是第1次内存申请请求。这时，从进程堆中申请一个分配单元个数为nInitSize的内存
块，并初始化该内存块（主要初始化MemoryBlock结构体成员，以及创建初始的自由分配单元链表，下面会详细分析其代码）。如果该内存块申请成功，
并初始化完毕，返回第1个分配单元给调用函数。第1个分配单元以MemoryBlock结构体内的最后一个字节为起始地址。</p>
<p>②处的作用是当内存池中已有内存块（即内存块链表不为空）时遍历该内存块链表，寻找还有"自由分配单元"的内存块。</p>
<p>③
处检查如果找到还有自由分配单元的内存块，则"定位"到该内存块现在可以用的自由分配单元处。"定位"以MemoryBlock结构体内的最后一个字节位
置aData为起始位置，以MemoryPool的nUnitSize为步长来进行。找到后，需要修改MemoryBlock的nFree信息（剩下来的
自由分配单元比原来减少了一个），以及修改此内存块的自由存储单元链表的信息。在找到的内存块中，pMyBlock-&gt;nFirst为该内存块中自
由存储单元链表的表头，其下一个自由存储单元的编号存放在pMyBlock-&gt;nFirst指示的自由存储单元（亦即刚才定位到的自由存储单元）的
头两个字节。通过刚才定位到的位置，取其头两个字节的值，赋给pMyBlock-&gt;nFirst，这就是此内存块的自由存储单元链表的新的表头，即
下一次分配出去的自由分配单元的编号（如果nFree大于零的话）。修改维护信息后，就可以将刚才定位到的自由分配单元的地址返回给此次申请的调用函数。
注意，因为这个分配单元已经被分配，而内存块无须维护已分配的分配单元，因此该分配单元的头两个字节的信息已经没有用处。换个角度看，这个自由分配单元返
回给调用函数后，调用函数如何处置这块内存，内存池无从知晓，也无须知晓。此分配单元在返回给调用函数时，其内容对于调用函数来说是无意义的。因此几乎可
以肯定调用函数在用这个单元的内存时会覆盖其原来的内容，即头两个字节的内容也会被抹去。因此每个存储单元并没有因为需要链接而引入多余的维护信息，而是
直接利用单元内的头两个字节，当其分配后，头两个字节也可以被调用函数利用。而在自由状态时，则用来存放维护信息，即下一个自由分配单元的编号，这是一个
有效利用内存的好例子。</p>
<p>④处表示在②处遍历时，没有找到还有自由分配单元的内存块，这时，需要重新向进程堆申
请一个内存块。因为不是第一次申请内存块，所以申请的内存块包含的分配单元个数为nGrowSize，而不再是nInitSize。与①处相同，先做这个
新申请内存块的初始化工作，然后将此内存块插入MemoryPool的内存块链表的头部，再将此内存块的第1个分配单元返回给调用函数。将此新内存块插入
内存块链表的头部的原因是该内存块还有很多可供分配的自由分配单元（除非nGrowSize等于1，这应该不太可能。因为内存池的含义就是一次性地从进程
堆中申请一大块内存，以供后续的多次申请），放在头部可以使得在下次收到内存申请时，减少②处对内存块的遍历时间。</p>
<p>可以用图6-2的MemoryPool来展示MemoryPool::Alloc的过程。图6-3是某个时刻MemoryPool的内部状态。</p>
<br><a name="N10215"><strong>图6-3  某个时刻MemoryPool的内部状态</strong></a><br>
<img alt="图6-3  某个时刻memorypool的内部状态" src="http://www.ibm.com/developerworks/cn/linux/l-cn-ppp/images6/6_3.gif" width="568" border="0" height="397">
<br>
<p>因
为MemoryPool的内存块链表不为空，因此会遍历其内存块链表。又因为第1个内存块里有自由的分配单元，所以会从第1个内存块中分配。检查
nFirst，其值为m，这时pBlock-&gt;aData+(pBlock-&gt;nFirst*nUnitSize)定位到编号为m的自由分配
单元的起始位置（用pFree表示）。在返回pFree之前，需要修改此内存块的维护信息。首先将nFree递减1，然后取得pFree处开始的头两个字
节的值（需要说明的是，这里aData处值为k。其实不是这一个字节。而是以aData和紧跟其后的另外一个字节合在一起构成的一个USHORT的值，不
可误会）。发现为k，这时修改pBlock的nFirst为k。然后，返回pFree。此时MemoryPool的结构如图6-4所示。</p>
<br><a name="N1022A"><strong>图6-4  MemoryPool的结构</strong></a><br>
<img alt="图6-4  memorypool的结构" src="http://www.ibm.com/developerworks/cn/linux/l-cn-ppp/images6/6_4.gif" width="521" border="0" height="373">
<br>
<p>可以看到，原来的第1个可供分配的单元（m编号处）已经显示为被分配的状态。而pBlock的nFirst已经指向原来m单元下一个自由分配单元的编号，即k。</p>
<p>（3）MemoryPool回收内存时：</p>
<br>
<table width="100%" border="0" cellpadding="0" cellspacing="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">void MemoryPool::Free( void* pFree )<br>{<br>    &#8230;&#8230;<br><br>    MemoryBlock* pMyBlock = pBlock;<br><br>    while ( ((ULONG)pMyBlock-&gt;aData &gt; (ULONG)pFree) ||<br>         ((ULONG)pFree &gt;= ((ULONG)pMyBlock-&gt;aData + pMyBlock-&gt;nSize)) )①<br>    {<br>         &#8230;&#8230;<br>    }<br><br>    pMyBlock-&gt;nFree++;                     ②<br>    *((USHORT*)pFree) = pMyBlock-&gt;nFirst;  ③<br>    pMyBlock-&gt;nFirst = (USHORT)(((ULONG)pFree-(ULONG)(pBlock-&gt;aData)) / nUnitSize);④<br><br>    if (pMyBlock-&gt;nFree*nUnitSize == pMyBlock-&gt;nSize )⑤<br>    {<br>        &#8230;&#8230;<br>    }<br>    else<br>    {<br>        &#8230;&#8230;<br>    }<br>}<br></pre>
            </td>
        </tr>
    </tbody>
</table>
<br>
<p>如前所述，回收分配单元时，可能会将整个内存块返回给进程堆，也可能将被回收分配单元所属的内存块移至内存池的内存块链表的头部。这两个操作都需要修改链表结构。这时需要知道该内存块在链表中前一个位置的内存块。</p>
<p>①处遍历内存池的内存块链表，确定该待回收分配单元（pFree）落在哪一个内存块的指针范围内，通过比较指针值来确定。</p>
<p>运
行到②处，pMyBlock即找到的包含pFree所指向的待回收分配单元的内存块（当然，这时应该还需要检查pMyBlock为NULL时的情形，即
pFree不属于此内存池的范围，因此不能返回给此内存池，读者可以自行加上）。这时将pMyBlock的nFree递增1，表示此内存块的自由分配单元
多了一个。</p>
<p>③处用来修改该内存块的自由分配单元链表的信息，它将这个待回收分配单元的头两个字节的值指向该内存块原来的第一个可分配的自由分配单元的编号。</p>
<p>④处将pMyBlock的nFirst值改变为指向这个待回收分配单元的编号，其编号通过计算此单元的起始位置相对pMyBlock的aData位置的差值，然后除以步长（nUnitSize）得到。</p>
<p>实
质上，③和④两步的作用就是将此待回收分配单元"真正回收"。值得注意的是，这两步实际上是使得此回收单元成为此内存块的下一个可分配的自由分配单元，即
将它放在了自由分配单元链表的头部。注意，其内存地址并没有发生改变。实际上，一个分配单元的内存地址无论是在分配后，还是处于自由状态时，一直都不会变
化。变化的只是其状态（已分配/自由），以及当其处于自由状态时在自由分配单元链表中的位置。</p>
<p>⑤处检查当回收完毕后，包含此回收单元的内存块的所有单元是否都处于自由状态，且此内存是否处于内存块链表的头部。如果是，将此内存块整个的返回给进程堆，同时修改内存块链表结构。</p>
<p>注
意，这里在判断一个内存块的所有单元是否都处于自由状态时，并没有遍历其所有单元，而是判断nFree乘以nUnitSize是否等于nSize。
nSize是内存块中所有分配单元的大小，而不包括头部MemoryBlock结构体的大小。这里可以看到其用意，即用来快速检查某个内存块中所有分配单
元是否全部处于自由状态。因为只需结合nFree和nUnitSize来计算得出结论，而无须遍历和计算所有自由状态的分配单元的个数。</p>
<p>另
外还需注意的是，这里并不能比较nFree与nInitSize或nGrowSize的大小来判断某个内存块中所有分配单元都为自由状态，这是因为第1次
分配的内存块（分配单元个数为nInitSize）可能被移到链表的后面，甚至可能在移到链表后面后，因为某个时间其所有单元都处于自由状态而被整个返回
给进程堆。即在回收分配单元时，无法判定某个内存块中的分配单元个数到底是nInitSize还是nGrowSize，也就无法通过比较nFree与
nInitSize或nGrowSize的大小来判断一个内存块的所有分配单元是否都为自由状态。</p>
<p>以上面分配后的内存池状态作为例子，假设这时第2个内存块中的最后一个单元需要回收（已被分配，假设其编号为m，pFree指针指向它），如图6-5所示。</p>
<p>不
难发现，这时nFirst的值由原来的0变为m。即此内存块下一个被分配的单元是m编号的单元，而不是0编号的单元（最先分配的是最新回收的单元，从这一
点看，这个过程与栈的原理类似，即先进后出。只不过这里的"进"意味着"回收"，而"出"则意味着"分配"）。相应地，m的"下一个自由单元"标记为0，
即内存块原来的"下一个将被分配出去的单元"，这也表明最近回收的分配单元被插到了内存块的"自由分配单元链表"的头部。当然，nFree递增1。</p>
<br><a name="N1026C"><strong>图6-5  分配后的内存池状态</strong></a><br>
<img alt="图6-5  分配后的内存池状态" src="http://www.ibm.com/developerworks/cn/linux/l-cn-ppp/images6/6_5.gif" width="458" border="0" height="328">
<br>
<p>处理至⑥处之前，其状态如图6-6所示。</p>
<br><a name="N10281"><strong>图6-6  处理至⑥处之前的内存池状态</strong></a><br>
<img alt="图6-6  处理至⑥处之前的内存池状态" src="http://www.ibm.com/developerworks/cn/linux/l-cn-ppp/images6/6_6.gif" width="535" border="0" height="365">
<br>
<p>这
里需要注意的是，虽然pFree被"回收"，但是pFree仍然指向m编号的单元，这个单元在回收过程中，其头两个字节被覆写，但其他部分的内容并没有改
变。而且从整个进程的内存使用角度来看，这个m编号的单元的状态仍然是"有效的"。因为这里的"回收"只是回收给了内存池，而并没有回收给进程堆，因此程
序仍然可以通过pFree访问此单元。但是这是一个很危险的操作，因为首先该单元在回收过程中头两个字节已被覆写，并且该单元可能很快就会被内存池重新分
配。因此回收后通过pFree指针对这个单元的访问都是错误的，读操作会读到错误的数据，写操作则可能会破坏程序中其他地方的数据，因此需要格外小心。</p>
<p>接着，需要判断该内存块的内部使用情况，及其在内存块链表中的位置。如果该内存块中省略号"&#8230;&#8230;"所表示的其他部分中还有被分配的单元，即nFree乘以nUnitSize不等于nSize。因为此内存块不在链表头，因此还需要将其移到链表头部，如图6-7所示。</p>
<br><a name="N10299"><strong>图6-7  因回收引起的MemoryBlock移动</strong></a><br>
<img alt="图6-7  因回收引起的memoryblock移动" src="http://www.ibm.com/developerworks/cn/linux/l-cn-ppp/images6/6_7.gif" width="508" border="0" height="333">
<br>
<p>如果该内存块中省略号"&#8230;&#8230;"表示的其他部分中全部都是自由分配单元，即nFree乘以nUnitSize等于nSize。因为此内存块不在链表头，所以此时需要将此内存块整个回收给进程堆，回收后内存池的结构如图6-8所示。</p>
<br><a name="N102AE"><strong>图6-8  回收后内存池的结构</strong></a><br>
<img alt="图6-8  回收后内存池的结构" src="http://www.ibm.com/developerworks/cn/linux/l-cn-ppp/images6/6_8.gif" width="322" border="0" height="346">
<br>
<p>一个内存块在申请后会初始化，主要是为了建立最初的自由分配单元链表，下面是其详细代码：</p>
<br>
<table width="100%" border="0" cellpadding="0" cellspacing="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">MemoryBlock::MemoryBlock (USHORT nTypes, USHORT nUnitSize)<br>	: nSize  (nTypes * nUnitSize),<br>	  nFree  (nTypes - 1),                     ④<br>	  nFirst (1),                              ⑤<br>	  pNext  (0)<br>{<br>		char * pData = aData;                  ①<br>		for (USHORT i = 1; i &lt; nTypes; i++) ②<br>		{<br>			*reinterpret_cast&lt;USHORT*&gt;(pData) = i; ③<br>			pData += nUnitSize;<br>		}<br>}<br></pre>
            </td>
        </tr>
    </tbody>
</table>
<br>
<p>这里可以看到，①处pData的初值是
aData，即0编号单元。但是②处的循环中i却是从1开始，然后在循环内部的③处将pData的头两个字节值置为i。即0号单元的头两个字节值为1，1
号单元的头两个字节值为2，一直到（nTypes-2）号单元的头两个字节值为（nTypes-1）。这意味着内存块初始时，其自由分配单元链表是从0号
开始。依次串联，一直到倒数第2个单元指向最后一个单元。</p>
<p>还需要注意的是，在其初始化列表中，nFree初始
化为nTypes-1（而不是nTypes），nFirst初始化为1（而不是0）。这是因为第1个单元，即0编号单元构造完毕后，立刻会被分配。另外注
意到最后一个单元初始并没有设置头两个字节的值，因为该单元初始在本内存块中并没有下一个自由分配单元。但是从上面例子中可以看到，当最后一个单元被分配
并回收后，其头两个字节会被设置。</p>
<p>图6-9所示为一个内存块初始化后的状态。</p>
<br><a name="N102D5"><strong>图6-9  一个内存块初始化后的状态</strong></a><br>
<img alt="图6-9  一个内存块初始化后的状态" src="http://www.ibm.com/developerworks/cn/linux/l-cn-ppp/images6/6_9.gif" width="199" border="0" height="327">
<br>
<p>当内存池析构时，需要将内存池的所有内存块返回给进程堆：</p>
<br>
<table width="100%" border="0" cellpadding="0" cellspacing="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">MemoryPool::~MemoryPool()<br>{<br>    MemoryBlock* pMyBlock = pBlock;<br>    while ( pMyBlock )<br>    {<br>        &#8230;&#8230;<br>    }<br>}<br></pre>
            </td>
        </tr>
    </tbody>
</table>
<br>
<p><a name="N102F1">6.2.4  使用方法</a></p>
<p>分
析内存池的内部原理后，本节说明如何使用它。从上面的分析可以看到，该内存池主要有两个对外接口函数，即Alloc和Free。Alloc返回所申请的分
配单元（固定大小内存），Free则回收传入的指针代表的分配单元的内存给内存池。分配的信息则通过MemoryPool的构造函数指定，包括分配单元大
小、内存池第1次申请的内存块中所含分配单元的个数，以及内存池后续申请的内存块所含分配单元的个数等。</p>
<p>综上
所述，当需要提高某些关键类对象的申请／回收效率时，可以考虑将该类所有生成对象所需的空间都从某个这样的内存池中开辟。在销毁对象时，只需要返回给该内
存池。"一个类的所有对象都分配在同一个内存池对象中"这一需求很自然的设计方法就是为这样的类声明一个静态内存池对象，同时为了让其所有对象都从这个内
存池中开辟内存，而不是缺省的从进程堆中获得，需要为该类重载一个new运算符。因为相应地，回收也是面向内存池，而不是进程的缺省堆，还需要重载一个
delete运算符。在new运算符中用内存池的Alloc函数满足所有该类对象的内存请求，而销毁某对象则可以通过在delete运算符中调用内存池的
Free完成。</p>
<p><a name="N102FD">6.2.5  性能比较</a></p>
<p>为
了测试利用内存池后的效果，通过一个很小的测试程序可以发现采用内存池机制后耗时为297 ms。而没有采用内存池机制则耗时625
ms，速度提高了52.48%。速度提高的原因可以归结为几点，其一，除了偶尔的内存申请和销毁会导致从进程堆中分配和销毁内存块外，绝大多数的内存申请
和销毁都由内存池在已经申请到的内存块中进行，而没有直接与进程堆打交道，而直接与进程堆打交道是很耗时的操作；其二，这是单线程环境的内存池，可以看到
内存池的Alloc和Free操作中并没有加线程保护措施。因此如果类A用到该内存池，则所有类A对象的创建和销毁都必须发生在同一个线程中。但如果类A
用到内存池，类B也用到内存池，那么类A的使用线程可以不必与类B的使用线程是同一个线程。</p>
<p>另外，在第1章中已经讨论过，因为内存池技术使得同类型的对象分布在相邻的内存区域，而程序会经常对同一类型的对象进行遍历操作。因此在程序运行过程中发生的缺页应该会相应少一些，但这个一般只能在真实的复杂应用环境中进行验证。</p>
<br>
<table width="100%" border="0" cellpadding="0" cellspacing="0">
    <tbody>
        <tr>
            <td><img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" width="100%" height="1"><br><img alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" height="6"></td>
        </tr>
    </tbody>
</table>
<table class="no-print" align="right" cellpadding="0" cellspacing="0">
    <tbody>
        <tr align="right">
            <td><img src="http://www.ibm.com/i/c.gif" alt="" width="100%" height="4"><br>
            <table border="0" cellpadding="0" cellspacing="0">
                <tbody>
                    <tr>
                        <td valign="middle"><img src="http://www.ibm.com/i/v14/icons/u_bold.gif" alt="" width="16" border="0" height="16"><br></td>
                        <td valign="top" align="right"><a href="http://www.ibm.com/developerworks/cn/linux/l-cn-ppp/index6.html?ca=drs-cn#main" class="fbox"><strong>回页首</strong></a></td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
<br><br>
<p><a name="N10309">6.3  本章小结</a></p>
<p>内
存的申请和释放对一个应用程序的整体性能影响极大，甚至在很多时候成为某个应用程序的瓶颈。消除内存申请和释放引起的瓶颈的方法往往是针对内存使用的实际
情况提供一个合适的内存池。内存池之所以能够提高性能，主要是因为它能够利用应用程序的实际内存使用场景中的某些"特性"。比如某些内存申请与释放肯定发
生在一个线程中，某种类型的对象生成和销毁与应用程序中的其他类型对象要频繁得多，等等。针对这些特性，可以为这些特殊的内存使用场景提供量身定做的内存
池。这样能够消除系统提供的缺省内存机制中，对于该实际应用场景中的不必要的操作，从而提升应用程序的整体性能。</p>
<br><br>
<p><a name="author">作者简介</a></p>
<table width="100%" border="0" cellpadding="0" cellspacing="0">
    <tbody>
        <tr>
            <td colspan="3"><img alt="" src="http://www.ibm.com/i/c.gif" width="100%" height="5"></td>
        </tr>
        <tr valign="top" align="left">
            <td><br></td>
            <td><img alt="" src="http://www.ibm.com/i/c.gif" width="4" height="5"></td>
            <td width="100%">
            <p>冯
            宏华，清华大学计算机科学与技术系硕士。IBM 中国开发中心高级软件工程师。 2003 年 12 月加入 IBM 中国开发中心，主要从事 IBM
            产品的开发、性能优化等工作。兴趣包括 C/C++ 应用程序性能调优，Windows 应用程序开发，Web 应用程序开发等。</p>
            </td>
        </tr>
    </tbody>
</table>
<br>
<table width="100%" border="0" cellpadding="0" cellspacing="0">
    <tbody>
        <tr>
            <td colspan="3"><img alt="" src="http://www.ibm.com/i/c.gif" width="100%" height="5"></td>
        </tr>
        <tr valign="top" align="left">
            <td><br></td>
            <td><img alt="" src="http://www.ibm.com/i/c.gif" width="4" height="5"></td>
            <td width="100%">
            <p>徐
            莹，山东大学计算机科学与技术系硕士。2003 年 4 月加入 IBM 中国开发中心，现任 IBM
            中国开发中心开发经理，一直从事IBM软件产品在多个操作系统平台上的开发工作。曾参与 IBM 产品在 Windows 和 Linux
            平台上的性能优化工作，对 C/C++ 编程语言和跨平台的大型软件系统的开发有较丰富的经验。</p>
            </td>
        </tr>
    </tbody>
</table>
<br>
<table width="100%" border="0" cellpadding="0" cellspacing="0">
    <tbody>
        <tr>
            <td colspan="3"><img alt="" src="http://www.ibm.com/i/c.gif" width="100%" height="5"></td>
        </tr>
        <tr valign="top" align="left">
            <td><br></td>
            <td><img alt="" src="http://www.ibm.com/i/c.gif" width="4" height="5"></td>
            <td width="100%">
            <p>程
            远，北京大学计算机科学与技术系硕士。IBM 中国开发中心高级软件工程师。2003 年加入 IBM 中国开发中心，主要从事IBM
            Productivity Tools 产品的开发、性能优化等工作。兴趣包括 C/C++ 编程语言，软件性能工程，Windows/Linux
            平台性能测试优化工具等。</p>
            </td>
        </tr>
    </tbody>
</table>
<br>
<table width="100%" border="0" cellpadding="0" cellspacing="0">
    <tbody>
        <tr>
            <td colspan="3"><img alt="" src="http://www.ibm.com/i/c.gif" width="100%" height="5"></td>
        </tr>
        <tr valign="top" align="left">
            <td><br></td>
            <td><img alt="" src="http://www.ibm.com/i/c.gif" width="4" height="5"></td>
            <td width="100%">
            <p>汪
            磊，北京航空航天大学计算机科学与技术系硕士，目前是 IBM 中国软件开发中心高级软件工程师。从 2002 年 12 月加入 IBM
            中国开发中心至今一直从事旨在提高企业生产效率的应用软件开发。兴趣包括 C\C++ 应用程序的性能调优，Java 应用程序的性能调优。</p>
            </td>
        </tr>
    </tbody>
</table>
<br><br><img src ="http://www.cppblog.com/michaelgao/aggbug/67122.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/michaelgao/" target="_blank">micheal's tech</a> 2008-11-17 16:37 <a href="http://www.cppblog.com/michaelgao/archive/2008/11/17/67122.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>编辑decorate程序时遇到一个问题</title><link>http://www.cppblog.com/michaelgao/archive/2008/10/16/64170.html</link><dc:creator>micheal's tech</dc:creator><author>micheal's tech</author><pubDate>Thu, 16 Oct 2008 09:04:00 GMT</pubDate><guid>http://www.cppblog.com/michaelgao/archive/2008/10/16/64170.html</guid><wfw:comment>http://www.cppblog.com/michaelgao/comments/64170.html</wfw:comment><comments>http://www.cppblog.com/michaelgao/archive/2008/10/16/64170.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/michaelgao/comments/commentRss/64170.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/michaelgao/services/trackbacks/64170.html</trackback:ping><description><![CDATA[class Decorator:public Beverage<br>{<br>&nbsp;&nbsp;&nbsp; public:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Decorator(Beverage * com);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; virtual ~Decorator();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; virtual string get_descrption();<br>&nbsp;&nbsp;&nbsp;<span style="background-color: yellow;"> protected:</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="background-color: yellow;">&nbsp; Beverage * component;</span><br><br><br>};<br><br>
而MilkDecorator继承了Decorator,如果component 为私有的则MilkDecorator便不能访问。<br><br>如果milkDecorator 设计成这样就不会违反了封装的原则。<br>基本上只有一个区别，就是protect成员能被派生类访问！而派生类对private没有特殊访问权！
<br><br><img src ="http://www.cppblog.com/michaelgao/aggbug/64170.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/michaelgao/" target="_blank">micheal's tech</a> 2008-10-16 17:04 <a href="http://www.cppblog.com/michaelgao/archive/2008/10/16/64170.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>为什么C++编译器不能支持对模板的分离式编译 </title><link>http://www.cppblog.com/michaelgao/archive/2008/10/09/63571.html</link><dc:creator>micheal's tech</dc:creator><author>micheal's tech</author><pubDate>Thu, 09 Oct 2008 09:23:00 GMT</pubDate><guid>http://www.cppblog.com/michaelgao/archive/2008/10/09/63571.html</guid><wfw:comment>http://www.cppblog.com/michaelgao/comments/63571.html</wfw:comment><comments>http://www.cppblog.com/michaelgao/archive/2008/10/09/63571.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/michaelgao/comments/commentRss/63571.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/michaelgao/services/trackbacks/63571.html</trackback:ping><description><![CDATA[<p>为什么C++编译器不能支持对模板的分离式编译 <br>刘未鹏(pongba) /文 </p>
<p>首先，C++标准中提到，一个编译单元[translation
unit]是指一个.cpp文件以及它所include的所有.h文件，.h文件里的代码将会被扩展到包含它的.cpp文件里，然后编译器编译该.cpp
文件为一个.obj文件，后者拥有PE[Portable
Executable,即windows可执行文件]文件格式，并且本身包含的就已经是二进制码，但是，不一定能够执行，因为并不保证其中一定有main
函数。当编译器将一个工程里的所有.cpp文件以分离的方式编译完毕后，再由连接器(linker)进行连接成为一个.exe文件。 <br>举个例子： <br>//---------------test.h-------------------// <br>void f();//这里声明一个函数f <br>//---------------test.cpp--------------// <br>＃i nclude&#8221;test.h&#8221; <br>void f() <br>{ <br>&#8230;//do something <br>} //这里实现出test.h中声明的f函数 <br>//---------------main.cpp--------------// <br>＃i nclude&#8221;test.h&#8221; <br>int main() <br>{ <br>f(); //调用f，f具有外部连接类型 <br>} <br>在
这个例子中，test.
cpp和main.cpp各被编译成为不同的.obj文件[姑且命名为test.obj和main.obj]，在main.cpp中，调用了f函数，然而
当编译器编译main.cpp时，它所仅仅知道的只是main.cpp中所包含的test.h文件中的一个关于void
f();的声明，所以，编译器将这里的f看作外部连接类型，即认为它的函数实现代码在另一个.obj文件中，本例也就是test.obj，也就是
说，main.obj中实际没有关于f函数的哪怕一行二进制代码，而这些代码实际存在于test.cpp所编译成的test.obj中。在
main.obj中对f的调用只会生成一行call指令，像这样： <br>call f [C++中这个名字当然是经过mangling[处理]过的] <br>在
编译时，这个call指令显然是错误的，因为main.obj中并无一行f的实现代码。那怎么办呢？这就是连接器的任务，连接器负责在其它的.obj中
[本例为test.obj]寻找f的实现代码，找到以后将call
f这个指令的调用地址换成实际的f的函数进入点地址。需要注意的是：连接器实际上将工程里的.obj&#8220;连接&#8221;成了一个.exe文件，而它最关键的任务就是
上面说的，寻找一个外部连接符号在另一个.obj中的地址，然后替换原来的&#8220;虚假&#8221;地址。 <br>这个过程如果说的更深入就是： <br>call f这行指令其实并不是这样的，它实际上是所谓的stub，也就是一个 <br>jmp
0x23423[这个地址可能是任意的，然而关键是这个地址上有一行指令来进行真正的call
f动作。也就是说，这个.obj文件里面所有对f的调用都jmp向同一个地址，在后者那儿才真正&#8221;call&#8221;f。这样做的好处就是连接器修改地址时只要对
后者的call
XXX地址作改动就行了。但是，连接器是如何找到f的实际地址的呢[在本例中这处于test.obj中]，因为.obj于.exe的格式都是一样的，在这
样的文件中有一个符号导入表和符号导出表[import table和export
table]其中将所有符号和它们的地址关联起来。这样连接器只要在test.obj的符号导出表中寻找符号f[当然C++对f作了mangling]的
地址就行了，然后作一些偏移量处理后[因为是将两个.obj文件合并，当然地址会有一定的偏移，这个连接器清楚]写入main.obj中的符号导入表中f
所占有的那一项。 <br>这就是大概的过程。其中关键就是： <br>编译main.cpp时，编译器不知道f的实现，所有当碰到对它的调用时只是给出一个指示，指示连接器应该为它寻找f的实现体。这也就是说main.obj中没有关于f的任何一行二进制代码。 <br>编译test.cpp时，编译器找到了f的实现。于是乎f的实现[二进制代码]出现在test.obj里。 <br>连接时，连接器在test.obj中找到f的实现代码[二进制]的地址[通过符号导出表]。然后将main.obj中悬而未决的call XXX地址改成f实际的地址。 <br>完成。 </p>
<p>然而，对于模板，你知道，模板函数的代码其实并不能直接编译成二进制代码，其中要有一个&#8220;具现化&#8221;的过程。举个例子： <br>//----------main.cpp------// <br>template&lt;class T&gt; <br>void f(T t) <br>{} <br>int main() <br>{ <br>&#8230;//do something <br>f(10); //call f&lt;int&gt; 编译器在这里决定给f一个f&lt;int&gt;的具现体 <br>&#8230;//do other thing <br>} <br>也就是说，如果你在main.cpp文件中没有调用过f，f也就得不到具现，从而main.obj中也就没有关于f的任意一行二进制代码！！如果你这样调用了： <br>f(10); //f&lt;int&gt;得以具现化出来 <br>f(10.0); //f&lt;double&gt;得以具现化出来 <br>这样main.obj中也就有了f&lt;int&gt;,f&lt;double&gt;两个函数的二进制代码段。以此类推。 <br>然而具现化要求编译器知道模板的定义，不是吗？ <br>看下面的例子：[将模板和它的实现分离] <br>//-------------test.h----------------// <br>template&lt;class T&gt; <br>class A <br>{ <br>public: <br>void f(); //这里只是个声明 <br>}; <br>//---------------test.cpp-------------// <br>＃i nclude&#8221;test.h&#8221; <br>template&lt;class T&gt; <br>void A&lt;T&gt;::f() //模板的实现，但注意：不是具现 <br>{ <br>&#8230;//do something <br>} <br>//---------------main.cpp---------------// <br>＃i nclude&#8221;test.h&#8221; <br>int main() <br>{ <br>A&lt;int&gt; a; <br>a. f(); //编译器在这里并不知道A&lt;int&gt;::f的定义，因为它不在test.h里面 <br>//于是编译器只好寄希望于连接器，希望它能够在其他.obj里面找到 <br>//A&lt;int&gt;::f的实现体,在本例中就是test.obj，然而，后者中真有A&lt;int&gt;::f的 <br>//二进制代码吗？NO！！！因为C++标准明确表示，当一个模板不被用到的时 <br>//侯它就不该被具现出来，test.cpp中用到了A&lt;int&gt;::f了吗？没有！！所以实 <br>//际上test.cpp编译出来的test.obj文件中关于A::f的一行二进制代码也没有 <br>//于是连接器就傻眼了，只好给出一个连接错误 <br>//
但是，如果在test.cpp中写一个函数，其中调用A&lt;int&gt;::f，则编译器会将其//具现出来，因为在这个点上[test.cpp
中]，编译器知道模板的定义，所以能//够具现化，于是，test.obj的符号导出表中就有了A&lt;int&gt;::f这个符号的地 <br>//址，于是连接器就能够完成任务。 <br>} </p>
<p>关键是：在分离式编译的环境下，编译器编译某一个.cpp文件时并不知道另一个.cpp文件的存在，也不会去查找[当遇到未决符号时它会寄希望于连
接器]。这种模式在没有模板的情况下运行良好，但遇到模板时就傻眼了，因为模板仅在需要的时候才会具现化出来，所以，当编译器只看到模板的声明时，它不能
具现化该模板，只能创建一个具有外部连接的符号并期待连接器能够将符号的地址决议出来。然而当实现该模板的.cpp文件中没有用到模板的具现体时，编译器
懒得去具现，所以，整个工程的.obj中就找不到一行模板具现体的二进制代码，于是连接器也黔</p>
<p>
</p>
<p>
</p>
<p>/////////////////////////////////<br><a href="http://dev.csdn.net/develop/article/19/19587.shtm">http://dev.csdn.net/develop/article/19/19587.shtm</a><br>&nbsp;C++模板代码的组织方式 ——包含模式（Inclusion Model）&nbsp;&nbsp;&nbsp;&nbsp; 选择自 sam1111 的 Blog&nbsp; <br>关键字&nbsp;&nbsp; Template Inclusion Model <br>出处&nbsp;&nbsp; C++ Template: The Complete Guide </p>
<p><br>说明：本文译自《C++ Template: The Complete Guide》一书的第6章中的部分内容。最近看到C++论坛上常有关于模板的包含模式的帖子，联想到自己初学模板时，也为类似的问题困惑过，因此翻译此文，希望对初学者有所帮助。 </p>
<p>模板代码有几种不同的组织方式，本文介绍其中最流行的一种方式：包含模式。 </p>
<p>链接错误 </p>
<p>大多数C/C++程序员向下面这样组织他们的非模板代码：</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#183;类和其他类型全部放在头文件中，这些头文件具有.hpp（或者.H, .h, .hh, .hxx）扩展名。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#183;对于全局变量和（非内联）函数，只有声明放在头文件中，而定义放在点C文件中，这些文件具有.cpp（或者.C, .c, .cc, .cxx）扩展名。<br>&nbsp;</p>
<p>这种组织方式工作的很好：它使得在编程时可以方便地访问所需的类型定义，并且避免了来自链接器的&#8220;变量或函数重复定义&#8221;的错误。<br>&nbsp;</p>
<p>由于以上组织方式约定的影响，模板编程新手往往会犯一个同样的错误。下面这一小段程序反映了这种错误。就像对待&#8220;普通代码&#8221;那样，我们在头文件中定义模板：<br>&nbsp;</p>
<p>// basics/myfirst.hpp&nbsp; </p>
<p>#ifndef MYFIRST_HPP <br>#define MYFIRST_HPP&nbsp; </p>
<p>// declaration of template </p>
<p>template &lt;typename T&gt; </p>
<p>void print_typeof (T const&amp;); </p>
<p>#endif // MYFIRST_HPP</p>
<p>&nbsp;</p>
<p>print_typeof()声明了一个简单的辅助函数用来打印一些类型信息。函数的定义放在点C文件中：</p>
<p>// basics/myfirst.cpp </p>
<p>＃i nclude &lt;iostream&gt; </p>
<p>＃i nclude &lt;typeinfo&gt; </p>
<p>＃i nclude "myfirst.hpp" <br>&nbsp;</p>
<p>// implementation/definition of template </p>
<p>template &lt;typename T&gt; <br>void print_typeof (T const&amp; x) <br>{ </p>
<p>&nbsp;&nbsp;&nbsp; std::cout &lt;&lt; typeid(x).name() &lt;&lt; std::endl; </p>
<p>} </p>
<p>&nbsp;</p>
<p>这个例子使用typeid操作符来打印一个字符串，这个字符串描述了传入的参数的类型信息。 </p>
<p>最后，我们在另外一个点C文件中使用我们的模板，在这个文件中模板声明被＃i nclude： </p>
<p>// basics/myfirstmain.cpp&nbsp; </p>
<p>＃i nclude "myfirst.hpp"&nbsp; </p>
<p>// use of the template </p>
<p>int main() <br>{ </p>
<p>&nbsp;&nbsp;&nbsp; double ice = 3.0; <br>&nbsp;&nbsp;&nbsp; print_typeof(ice);&nbsp; // call function template for type double </p>
<p>} </p>
<p>&nbsp;<br>大部分C++编译器（Compiler）很可能会接受这个程序，没有任何问题，但是链接器（Linker）大概会报告一个错误，指出缺少函数print_typeof()的定义。 </p>
<p>这个错误的原因在于，模板函数print_typeof()的定义还没有被具现化（instantiate）。为了具现化一个模板，编译器必须知道
哪一个定义应该被具现化，以及使用什么样的模板参数来具现化。不幸的是，在前面的例子中，这两组信息存在于分开编译的不同文件中。因此，当我们的编译器看
到对print_typeof()的调用，但是没有看到此函数为double类型具现化的定义时，它只是假设这样的定义在别处提供，并且创建一个那个定义
的引用（链接器使用此引用解析）。另一方面，当编译器处理myfirst.cpp时，该文件并没有任何指示表明它必须为它所包含的特殊参数具现化模板定
义。</p>
<p>头文件中的模板 </p>
<p>解决上面这个问题的通用解法是，采用与我们使用宏或者内联函数相同的方法：我们将模板的定义包含进声明模板的头文件中。对于我们的例子，我们可以通
过将＃i nclude
"myfirst.cpp"添加到myfirst.hpp文件尾部，或者在每一个使用我们的模板的点C文件中包含myfirst.cpp文件，来达到目
的。当然，还有第三种方法，就是删掉myfirst.cpp文件，并重写myfirst.hpp文件，使它包含所有的模板声明与定义：</p>
<p><br>// basics/myfirst2.hpp </p>
<p>#ifndef MYFIRST_HPP <br>#define MYFIRST_HPP&nbsp; </p>
<p>＃i nclude &lt;iostream&gt; <br>＃i nclude &lt;typeinfo&gt; <br>&nbsp;</p>
<p>// declaration of template <br>template &lt;typename T&gt; <br>void print_typeof (T const&amp;);&nbsp; </p>
<p>// implementation/definition of template <br>template &lt;typename T&gt; <br>void print_typeof (T const&amp; x) <br>{ </p>
<p>&nbsp;&nbsp;&nbsp; std::cout &lt;&lt; typeid(x).name() &lt;&lt; std::endl; </p>
<p>} </p>
<p>#endif // MYFIRST_HPP</p>
<p>&nbsp;</p>
<p>这种组织模板代码的方式就称作包含模式。经过这样的调整，你会发现我们的程序已经能够正确编译、链接、执行了。 </p>
<p>从这个方法中我们可以得到一些观察结果。最值得注意的一点是，这个方法在相当程度上增加了包含myfirst.hpp的开销。在这个例子中，这种开
销并不是由模板定义自身的尺寸引起的，而是由这样一个事实引起的，即我们必须包含我们的模板用到的头文件，在这个例子中
是&lt;iostream&gt;和&lt;typeinfo&gt;。你会发现这最终导致了成千上万行的代码，因为诸
如&lt;iostream&gt;这样的头文件也包含了和我们类似的模板定义。 </p>
<p>这在实践中确实是一个问题，因为它增加了编译器在编译一个实际程序时所需的时间。我们因此会在以后的章节中验证其他一些可能的方法来解决这个问题。但无论如何，现实世界中的程序花一小时来编译链接已经是快的了（我们曾经遇到过花费数天时间来从源码编译的程序）。 </p>
<p>抛开编译时间不谈，我们强烈建议如果可能尽量按照包含模式组织模板代码。 </p>
<p>另一个观察结果是，非内联模板函数与内联函数和宏的最重要的不同在于：它并不会在调用端展开。相反，当模板函数被具现化时，会产生此函数的一个新的
拷贝。由于这是一个自动的过程，编译器也许会在不同的文件中产生两个相同的拷贝，从而引起链接器报告一个错误。理论上，我们并不关心这一点：这是编译器设
计者应当关心的事情。实际上，大多数时候一切都运转正常，我们根本就不用处理这种状况。然而，对于那些需要创建自己的库的大型项目，这个问题偶尔会显现出
来。<br>&nbsp;</p>
<p>最后，需要指出的是，在我们的例子中，应用于普通模板函数的方法同样适用于模板类的成员函数和静态数据成员，以及模板成员函数。</p>
<p><br></p>
<br><img src ="http://www.cppblog.com/michaelgao/aggbug/63571.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/michaelgao/" target="_blank">micheal's tech</a> 2008-10-09 17:23 <a href="http://www.cppblog.com/michaelgao/archive/2008/10/09/63571.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C++中接口与实现的分离句柄类</title><link>http://www.cppblog.com/michaelgao/archive/2008/10/07/63401.html</link><dc:creator>micheal's tech</dc:creator><author>micheal's tech</author><pubDate>Tue, 07 Oct 2008 08:13:00 GMT</pubDate><guid>http://www.cppblog.com/michaelgao/archive/2008/10/07/63401.html</guid><wfw:comment>http://www.cppblog.com/michaelgao/comments/63401.html</wfw:comment><comments>http://www.cppblog.com/michaelgao/archive/2008/10/07/63401.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/michaelgao/comments/commentRss/63401.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/michaelgao/services/trackbacks/63401.html</trackback:ping><description><![CDATA[<pre>
<div>句柄类是存储和管理基类指针的一个类 <br> 需要句柄类的背景： <br> 1）在对安全要求很高的领域，即使核心实现已经封闭在库中不可见，但头文件中变量定义仍可能曝露一些内部信息 <br> 2）在设计初期、实现部分会经常变动，甚至头文件中变量定义也需要经常变动，因此在重编译的时候头文件也需要编译，<br>有时候导致编译时间过长。<br> 句柄类就是为了解决这类问题
<br>// Handle.h<br>class Implement; //这里是对真正实现功能的类的声明<br><br>class ImplementHandle //这是Implement类的句柄类<br>{<br>public:<br>ImplementHandle():lpImplementInstance(NULL){lpImplementInstance = new Implement;}<br>~ImplementHandle(){ delete lpImplementInstance ;}<br>public:<br>// Interface_FOO() 是句柄类提供的接口，它的真正实现是在Implement类里面,而这个仅仅是接口"代理"<br>RE_TYPE Interface_FOO()<br>{<br>return lpImplementInstance-&gt;FOO
<div style="border: 1px solid #666666;">_</div>
Implementation(); //句柄代理调用实现真正的FOO接口<br>}<br>//还有其他的接口也一样，均是用句柄类代理接口<br>//....<br>private:<br>Implement * lpImplementInstance; //这个是句柄类唯一的数据成员(当然，并不一定),可以被句柄类很好地自动管理<br>};<br><br><br><br><br>&nbsp; 被封装在句柄类里面的真正实现（class Implement）将与用户隔离开来，就是说，就算以后Implement 类的实现有所改变，<br>只要它提供的接口不变，那么它的句柄类就不会改变，而包含句柄类的用户，也不用做任何相应的改变（所有包含 &#8220;Handle.h&#8221;的模块甚至不用从新编译就可以正常更新至最新的Implement实现）。<br><br>例如<br>    #include "Handle.h"<br>    Imlementhandle testhandle;<br>    testhandle-&gt;Interface_Foo();//调用接口即可。<br>    如果改动了Implent类的方法<br><br>&nbsp; 于此相反，如果直接用class Implement 的定义，那么只要Implement类的定义有所改变（不管是public 还是private 成员<br>的更新），那么所有包含它的头文件的模块都要从新编译一次。<br><br>这其实就是接口与实现的分离，
<br></div>
<br></pre>
<br> <img src ="http://www.cppblog.com/michaelgao/aggbug/63401.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/michaelgao/" target="_blank">micheal's tech</a> 2008-10-07 16:13 <a href="http://www.cppblog.com/michaelgao/archive/2008/10/07/63401.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C++实现设计模式中的Interface from goolge</title><link>http://www.cppblog.com/michaelgao/archive/2008/10/07/63392.html</link><dc:creator>micheal's tech</dc:creator><author>micheal's tech</author><pubDate>Tue, 07 Oct 2008 06:39:00 GMT</pubDate><guid>http://www.cppblog.com/michaelgao/archive/2008/10/07/63392.html</guid><wfw:comment>http://www.cppblog.com/michaelgao/comments/63392.html</wfw:comment><comments>http://www.cppblog.com/michaelgao/archive/2008/10/07/63392.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/michaelgao/comments/commentRss/63392.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/michaelgao/services/trackbacks/63392.html</trackback:ping><description><![CDATA[Classes that satisfy certain conditions are allowed, but not required, to
end with an <code>Interface</code> suffix.
<br><a href="http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml?showone=Interfaces#Interfaces">
link
</a>
<p>Definition:
</p>
<p>
A class is a pure interface if it meets the following requirements:
</p>
<ul>
    <li> It has only public pure virtual ("<code>= 0</code>") methods
    and static methods (but see below for destructor).
    </li>
    <li> It may not have non-static data members.
    </li>
    <li> It need not have any constructors defined.  If a constructor is
    provided, it must take no arguments and it must be protected.
    </li>
    <li> If it is a subclass, it may only be derived from classes
    that satisfy these conditions and are tagged with the
    <code>Interface</code> suffix.
    </li>
</ul>
<p>
An interface class can never be directly instantiated
because of the pure virtual method(s) it declares.  To make
sure all implementations of the interface can be destroyed
correctly, they must also declare a virtual destructor (in
an exception to the first rule, this should not be pure).  See
Stroustrup, <cite>The C++ Programming Language</cite>, 3rd
edition, section 12.4 for details.
</p>
<p>Pros:
Tagging a class with the <code>Interface</code> suffix lets
others know that they must not add implemented methods or non
static data members.  This is particularly important in the case of
<a href="http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Multiple_Inheritance">multiple inheritance</a>.
Additionally, the interface concept is already well-understood by
Java programmers.
</p>
<p>Cons:
The <code>Interface</code> suffix lengthens the class name, which
can make it harder to read and understand.  Also, the interface
property may be considered an implementation detail that shouldn't
be exposed to clients.
</p>
<p>Decision:
A class may end with <code>Interface</code> only if it meets the
above requirements.  We do not require the converse, however:
classes that meet the above requirements are not required to end
with <code>Interface</code>.
</p>
<br> <img src ="http://www.cppblog.com/michaelgao/aggbug/63392.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/michaelgao/" target="_blank">micheal's tech</a> 2008-10-07 14:39 <a href="http://www.cppblog.com/michaelgao/archive/2008/10/07/63392.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>virtual destruct （确定基类有虚析构函数）</title><link>http://www.cppblog.com/michaelgao/archive/2008/07/08/55646.html</link><dc:creator>micheal's tech</dc:creator><author>micheal's tech</author><pubDate>Tue, 08 Jul 2008 09:10:00 GMT</pubDate><guid>http://www.cppblog.com/michaelgao/archive/2008/07/08/55646.html</guid><wfw:comment>http://www.cppblog.com/michaelgao/comments/55646.html</wfw:comment><comments>http://www.cppblog.com/michaelgao/archive/2008/07/08/55646.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/michaelgao/comments/commentRss/55646.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/michaelgao/services/trackbacks/55646.html</trackback:ping><description><![CDATA[保证基类的也被调用。什么情况下使用比较好呢。<br><br>#include &lt;iostream&gt;<br>using namespace std;<br>class Base{<br>&nbsp;&nbsp;&nbsp; private:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int num1;<br>&nbsp;&nbsp;&nbsp; public:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Base():num1(10)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; virtual ~Base()<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cout&lt;&lt;"base"&lt;&lt;endl;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>};<br>class Dervied:public Base{<br>&nbsp;&nbsp;&nbsp; private:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int num2;<br>&nbsp;&nbsp;&nbsp; public:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Dervied():num2(1)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ~Dervied()<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cout&lt;&lt;"Dervied"&lt;&lt;endl;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>};<br>int main()<br>{<br>&nbsp;&nbsp;&nbsp; Base *pBase = new Dervied();<br>&nbsp;&nbsp;&nbsp; delete pBase;<br>}<br><br>结果会<br>Dervied <br>Base<br>#include&lt;iostream&gt;<br>using namespace std;<br><br>class ClxBase<br>{<br>&nbsp;&nbsp;&nbsp; public:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ClxBase() {};<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ~ClxBase() {cout&lt;&lt;"Do base class destruct"&lt;&lt;endl;};<br><br>};<br><br>class ClxDerived : public ClxBase<br>{<br>&nbsp;&nbsp;&nbsp; public:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ClxDerived() {};<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ~ClxDerived() { cout &lt;&lt; "Do derived class destruct!" &lt;&lt; endl; };<br><br>};<br><br><br>int main()<br>{<br><br>&nbsp;&nbsp;&nbsp; ClxBase *pTest = new ClxDerived;<br>&nbsp;&nbsp;&nbsp; ClxDerived derived;<br><br>&nbsp;&nbsp;&nbsp; delete pTest;<br><br>}<br>另一个例子输出的却是 :<br>Do base class destruct<br>Do derived class destruct!<br>Do base class destruct<br><br style="color: red;"><span style="color: red;">说明了两个问题，只想派生类对象的基类指针需要基类声明虚系构函数才能调用派生类指针，而派生类对象却不用基类声明虚系构函数就能调用派生类指针
</span><br>
<br>
<br>   <img src ="http://www.cppblog.com/michaelgao/aggbug/55646.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/michaelgao/" target="_blank">micheal's tech</a> 2008-07-08 17:10 <a href="http://www.cppblog.com/michaelgao/archive/2008/07/08/55646.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>malloc free realloc重新重载</title><link>http://www.cppblog.com/michaelgao/archive/2008/06/06/52374.html</link><dc:creator>micheal's tech</dc:creator><author>micheal's tech</author><pubDate>Fri, 06 Jun 2008 09:02:00 GMT</pubDate><guid>http://www.cppblog.com/michaelgao/archive/2008/06/06/52374.html</guid><wfw:comment>http://www.cppblog.com/michaelgao/comments/52374.html</wfw:comment><comments>http://www.cppblog.com/michaelgao/archive/2008/06/06/52374.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/michaelgao/comments/commentRss/52374.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/michaelgao/services/trackbacks/52374.html</trackback:ping><description><![CDATA[为了调试写关于线程的信息，主要是core dump的信息，可以重载或者代替<br>malloc<br>free<br>realloc<br>函数，dmalloc 这个便是其这个作用的。但是由于dbmalloc性能影响较大。可以采用轻量级的重载，在malloc free realloc填充字符。最终通过core dump文件可以看到原因。<br>方案措施开始想到用dlopen,dlsymbol,dlload这种方案，但是这种方案会重复调用。是不可能实现的，最终采用的只能是用宏来代替。基本的方案就是定义一个公用的头文件，这个头文件的宏发生了变化，然后每个调用malloc,free等的都要包含头文件。当然在引用头文件的时候我们也要定义一个c/c++文件来重新实现，他不需要包含这个头文件。<br><br>在过程中遇到的问题<br>1、头文件的包含顺序，应该放在后面才会重新定义。<br>2、C/C++混合，malloc等是C的函数。<br>3、realloc会重新改变位置，比较容易出错的。<br>4、free(0)是可以的，要注意出错。<br><br>  <img src ="http://www.cppblog.com/michaelgao/aggbug/52374.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/michaelgao/" target="_blank">micheal's tech</a> 2008-06-06 17:02 <a href="http://www.cppblog.com/michaelgao/archive/2008/06/06/52374.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C/C++头文件</title><link>http://www.cppblog.com/michaelgao/archive/2008/06/05/52268.html</link><dc:creator>micheal's tech</dc:creator><author>micheal's tech</author><pubDate>Thu, 05 Jun 2008 09:19:00 GMT</pubDate><guid>http://www.cppblog.com/michaelgao/archive/2008/06/05/52268.html</guid><wfw:comment>http://www.cppblog.com/michaelgao/comments/52268.html</wfw:comment><comments>http://www.cppblog.com/michaelgao/archive/2008/06/05/52268.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/michaelgao/comments/commentRss/52268.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/michaelgao/services/trackbacks/52268.html</trackback:ping><description><![CDATA[1、提供了一个全局的声明，全局函数、变量的一致性。<br>2、如果要修改功能仅仅需要简单修改头文件。<br><br><br> <img src ="http://www.cppblog.com/michaelgao/aggbug/52268.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/michaelgao/" target="_blank">micheal's tech</a> 2008-06-05 17:19 <a href="http://www.cppblog.com/michaelgao/archive/2008/06/05/52268.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[导入]extern "C"用法</title><link>http://www.cppblog.com/michaelgao/archive/2008/06/05/52246.html</link><dc:creator>micheal's tech</dc:creator><author>micheal's tech</author><pubDate>Thu, 05 Jun 2008 07:59:00 GMT</pubDate><guid>http://www.cppblog.com/michaelgao/archive/2008/06/05/52246.html</guid><wfw:comment>http://www.cppblog.com/michaelgao/comments/52246.html</wfw:comment><comments>http://www.cppblog.com/michaelgao/archive/2008/06/05/52246.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/michaelgao/comments/commentRss/52246.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/michaelgao/services/trackbacks/52246.html</trackback:ping><description><![CDATA[extern "C"<br>
<img src="http://www.cnblogs.com/michael-gao/aggbug/1214470.html?type=1" width="1" height="1"><br>
<meta http-equiv="Content-Type" content="text/html; charset=" utf-8="">
<meta name="ProgId" content="Word.Document">
<meta name="Generator" content="Microsoft Word 11">
<meta name="Originator" content="Microsoft Word 11">
<link rel="File-List" href="file:///D:%5CProfiles%5Ckrq784%5CLOCALS%7E1%5CTemp%5Cmsohtml1%5C01%5Cclip_filelist.xml"><!--[if gte mso 9]><xml>
<w:worddocument>
<w:view>Normal</w:view>
<w:zoom>0</w:zoom>
<w:punctuationkerning/>
<w:drawinggridverticalspacing>7.8 pt</w:drawinggridverticalspacing>
<w:displayhorizontaldrawinggridevery>0</w:displayhorizontaldrawinggridevery>
<w:displayverticaldrawinggridevery>2</w:displayverticaldrawinggridevery>
<w:validateagainstschemas/>
<w:saveifxmlinvalid>false</w:saveifxmlinvalid>
<w:ignoremixedcontent>false</w:ignoremixedcontent>
<w:alwaysshowplaceholdertext>false</w:alwaysshowplaceholdertext>
<w:compatibility>
<w:spaceforul/>
<w:balancesinglebytedoublebytewidth/>
<w:donotleavebackslashalone/>
<w:ultrailspace/>
<w:donotexpandshiftreturn/>
<w:adjustlineheightintable/>
<w:breakwrappedtables/>
<w:snaptogridincell/>
<w:wraptextwithpunct/>
<w:useasianbreakrules/>
<w:dontgrowautofit/>
<w:usefelayout/>
</w:compatibility>
<w:browserlevel>MicrosoftInternetExplorer4</w:browserlevel>
</w:worddocument>
</xml><![endif]--><!--[if gte mso 9]><xml>
<w:latentstyles deflockedstate="false" latentstylecount="156">
</w:latentstyles>
</xml><![endif]--><style>
<!--
/* Font Definitions */
@font-face
{font-family:宋体;
panose-1:2 1 6 0 3 1 1 1 1 1;
mso-font-alt:SimSun;
mso-font-charset:134;
mso-generic-font-family:auto;
mso-font-pitch:variable;
mso-font-signature:3 135135232 16 0 262145 0;}
@font-face
{font-family:"\@宋体";
panose-1:2 1 6 0 3 1 1 1 1 1;
mso-font-charset:134;
mso-generic-font-family:auto;
mso-font-pitch:variable;
mso-font-signature:3 135135232 16 0 262145 0;}
/* Style Definitions */
p.MsoNormal, li.MsoNormal, div.MsoNormal
{mso-style-parent:"";
margin:0cm;
margin-bottom:.0001pt;
text-align:justify;
text-justify:inter-ideograph;
mso-pagination:none;
font-size:10.5pt;
mso-bidi-font-size:12.0pt;
font-family:"Times New Roman";
mso-fareast-font-family:宋体;
mso-font-kerning:1.0pt;}
/* Page Definitions */
@page
{mso-page-border-surround-header:no;
mso-page-border-surround-footer:no;}
@page Section1
{size:612.0pt 792.0pt;
margin:72.0pt 90.0pt 72.0pt 90.0pt;
mso-header-margin:36.0pt;
mso-footer-margin:36.0pt;
mso-paper-source:0;}
div.Section1
{page:Section1;}
-->
</style><!--[if gte mso 10]>
<style>
/* Style Definitions */
table.MsoNormalTable
{mso-style-name:"Table Normal";
mso-tstyle-rowband-size:0;
mso-tstyle-colband-size:0;
mso-style-noshow:yes;
mso-style-parent:"";
mso-padding-alt:0cm 5.4pt 0cm 5.4pt;
mso-para-margin:0cm;
mso-para-margin-bottom:.0001pt;
mso-pagination:widow-orphan;
font-size:10.0pt;
font-family:"Times New Roman";
mso-fareast-font-family:"Times New Roman";
mso-ansi-language:#0400;
mso-fareast-language:#0400;
mso-bidi-language:#0400;}
</style>
<![endif]--><span style="font-size: 10.5pt; font-family: &quot;times new roman&quot;;" lang="EN-US">extern "C" </span><span style="font-size: 10.5pt; font-family: 宋体;">链接指示符不能在函数体内定义。</span><span style="font-size: 10.5pt; font-family: &quot;times new roman&quot;;" lang="EN-US"><br>
extern "Fortran"<br>
</span><span style="font-size: 10.5pt; font-family: 宋体;">等等。</span><span style="font-size: 10.5pt; font-family: &quot;times new roman&quot;;" lang="EN-US"><br>
<br>
extern"C"</span><span style="font-size: 10.5pt; font-family: 宋体;">为了混合联编而出现的。</span><span style="font-size: 10.5pt; font-family: &quot;times new roman&quot;;" lang="EN-US"><br>
1</span><span style="font-size: 10.5pt; font-family: 宋体;">、</span><span style="font-size: 10.5pt; font-family: &quot;times new roman&quot;;" lang="EN-US"><br>
C++</span><span style="font-size: 10.5pt; font-family: 宋体;">中引用</span><span style="font-size: 10.5pt; font-family: &quot;times new roman&quot;;" lang="EN-US">C</span><span style="font-size: 10.5pt; font-family: 宋体;">的头文件，然后包括</span><span style="font-size: 10.5pt; font-family: &quot;times new roman&quot;;" lang="EN-US">library</span><span style="font-size: 10.5pt; font-family: 宋体;">和</span><span style="font-size: 10.5pt; font-family: &quot;times new roman&quot;;" lang="EN-US">dll</span><span style="font-size: 10.5pt; font-family: 宋体;">动态和静态的加载了。例如：</span><span style="font-size: 10.5pt; font-family: &quot;times new roman&quot;;" lang="EN-US"><br>
extern "C" <br>
{<br>
&nbsp;&nbsp;&nbsp; #include&nbsp; "Cheader.h"<br>
}<br>
&nbsp;#pragment mylib</span><span style="font-size: 10.5pt; font-family: 宋体;">等。</span><span style="font-size: 10.5pt; font-family: &quot;times new roman&quot;;" lang="EN-US"><br>
/*</span><span style="font-size: 10.5pt; font-family: 宋体;">引用</span><span style="font-size: 10.5pt; font-family: &quot;times new roman&quot;;" lang="EN-US">Cheader</span><span style="font-size: 10.5pt; font-family: 宋体;">中的函数了</span><span style="font-size: 10.5pt; font-family: &quot;times new roman&quot;;" lang="EN-US">*/<br>
</span><span style="font-size: 10.5pt; font-family: 宋体;">或者可以</span><span style="font-size: 10.5pt; font-family: &quot;times new roman&quot;;" lang="EN-US">extern "C"</span><span style="font-size: 10.5pt; font-family: 宋体;">的函数。</span><span style="font-size: 10.5pt; font-family: &quot;times new roman&quot;;" lang="EN-US"><br>
<br>
</span><span style="font-size: 10.5pt; font-family: 宋体;">所以标准的头文件中就会出现：</span><span style="font-size: 10.5pt; font-family: &quot;times new roman&quot;;" lang="EN-US"><br>
#ifdef __cplusplus<br>
extern "C" {<br>
#endif <br>
/*...*/ <br>
#ifdef __cplusplus<br>
}<br>
#endif <br>
</span><span style="font-size: 10.5pt; font-family: 宋体;">这样是为了使得</span><span style="font-size: 10.5pt; font-family: &quot;times new roman&quot;;" lang="EN-US">C++</span><span style="font-size: 10.5pt; font-family: 宋体;">引用头文件不用再添加这个</span><span style="font-size: 10.5pt; font-family: &quot;times new roman&quot;;" lang="EN-US">extern "C" {...}<br>
<br>
2</span><span style="font-size: 10.5pt; font-family: 宋体;">、</span><span style="font-size: 10.5pt; font-family: &quot;times new roman&quot;;" lang="EN-US">C</span><span style="font-size: 10.5pt; font-family: 宋体;">引用</span><span style="font-size: 10.5pt; font-family: &quot;times new roman&quot;;" lang="EN-US">C++</span><span style="font-size: 10.5pt; font-family: 宋体;">的函数的时候要注意</span><span style="font-size: 10.5pt; font-family: &quot;times new roman&quot;;" lang="EN-US">,</span><span style="font-size: 10.5pt; font-family: 宋体;">此时</span><span style="font-size: 10.5pt; font-family: &quot;times new roman&quot;;" lang="EN-US">C++</span><span style="font-size: 10.5pt; font-family: 宋体;">的头文件应该包含着</span><span style="font-size: 10.5pt; font-family: &quot;times new roman&quot;;" lang="EN-US">extern "C"</span><span style="font-size: 10.5pt; font-family: 宋体;">，但是在</span><span style="font-size: 10.5pt; font-family: &quot;times new roman&quot;;" lang="EN-US">C</span><span style="font-size: 10.5pt; font-family: 宋体;">语言中不能直接引用声明了</span><span style="font-size: 10.5pt; font-family: &quot;times new roman&quot;;" lang="EN-US">extern "C"</span><span style="font-size: 10.5pt; font-family: 宋体;">的该头文件，应该仅将</span><span style="font-size: 10.5pt; font-family: &quot;times new roman&quot;;" lang="EN-US">C</span><span style="font-size: 10.5pt; font-family: 宋体;">文件中将</span><span style="font-size: 10.5pt; font-family: &quot;times new roman&quot;;" lang="EN-US">C++</span><span style="font-size: 10.5pt; font-family: 宋体;">中定义的</span><span style="font-size: 10.5pt; font-family: &quot;times new roman&quot;;" lang="EN-US">extern "C"</span><span style="font-size: 10.5pt; font-family: 宋体;">函数声明为</span><span style="font-size: 10.5pt; font-family: &quot;times new roman&quot;;" lang="EN-US">extern</span><span style="font-size: 10.5pt; font-family: 宋体;">类型。</span><br><br>
<div align="right"><a style="text-decoration: none;" href="http://michael-gao.cnblogs.com/" target="_blank">michalegao</a> 2008-06-05 14:42 <a href="http://www.cnblogs.com/michael-gao/archive/2008/06/05/1214470.html#Feedback" target="_blank" style="text-decoration: none;">发表评论</a></div>
<br>文章来源:<a href="http://www.cnblogs.com/michael-gao/archive/2008/06/05/1214470.html">http://www.cnblogs.com/michael-gao/archive/2008/06/05/1214470.html</a>  <img src ="http://www.cppblog.com/michaelgao/aggbug/52246.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/michaelgao/" target="_blank">micheal's tech</a> 2008-06-05 15:59 <a href="http://www.cppblog.com/michaelgao/archive/2008/06/05/52246.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[导入]new 表达式(placement new expression)</title><link>http://www.cppblog.com/michaelgao/archive/2008/06/05/52247.html</link><dc:creator>micheal's tech</dc:creator><author>micheal's tech</author><pubDate>Thu, 05 Jun 2008 07:59:00 GMT</pubDate><guid>http://www.cppblog.com/michaelgao/archive/2008/06/05/52247.html</guid><wfw:comment>http://www.cppblog.com/michaelgao/comments/52247.html</wfw:comment><comments>http://www.cppblog.com/michaelgao/archive/2008/06/05/52247.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/michaelgao/comments/commentRss/52247.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/michaelgao/services/trackbacks/52247.html</trackback:ping><description><![CDATA[Operator new allocates memory from the heap, on which an object is
constructed. Standard C++ also supports placement new operator, which
constructs an object on a pre-allocated buffer. This is useful when
building a memory pool, a garbage collector or simply when performance
and exception safety are paramount (there's no danger of allocation
failure since the memory has already been allocated, and constructing
an object on a pre-allocated buffer takes less time):
<pre><code> void placement() {<br>
<br>
char *buf  = new char[1000];   //pre-allocated buffer<br>
<br>
string *p = new (buf) string("hi");  //placement new<br>
<br>
string *q = new string("hi");  //ordinary heap allocation<br>
<br>
cout&lt;</code><code>&lt;</code><code><br>
<p->c_str()</p->
<br>
</code><code>&lt;</code><code><br>
<p->&lt;<q->c_str();<br>
<br>
}<br>
<strong>：<br>
placement new 表达式只是定位，不存在与其相对应的delete，如果delete则选择<br>
delete[] buf。</strong></q-></p->
</code></pre>
<img src="http://www.cnblogs.com/michael-gao/aggbug/1214239.html?type=1" width="1" height="1"><br><br>
<div align="right"><a style="text-decoration: none;" href="http://michael-gao.cnblogs.com/" target="_blank">michalegao</a> 2008-06-05 12:03 <a href="http://www.cnblogs.com/michael-gao/archive/2008/06/05/1214239.html#Feedback" target="_blank" style="text-decoration: none;">发表评论</a></div>
<br>文章来源:<a href="http://www.cnblogs.com/michael-gao/archive/2008/06/05/1214239.html">http://www.cnblogs.com/michael-gao/archive/2008/06/05/1214239.html</a> <img src ="http://www.cppblog.com/michaelgao/aggbug/52247.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/michaelgao/" target="_blank">micheal's tech</a> 2008-06-05 15:59 <a href="http://www.cppblog.com/michaelgao/archive/2008/06/05/52247.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[导入]C++  new的实现，与C的malloc的关系。</title><link>http://www.cppblog.com/michaelgao/archive/2008/06/05/52248.html</link><dc:creator>micheal's tech</dc:creator><author>micheal's tech</author><pubDate>Thu, 05 Jun 2008 07:59:00 GMT</pubDate><guid>http://www.cppblog.com/michaelgao/archive/2008/06/05/52248.html</guid><wfw:comment>http://www.cppblog.com/michaelgao/comments/52248.html</wfw:comment><comments>http://www.cppblog.com/michaelgao/archive/2008/06/05/52248.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/michaelgao/comments/commentRss/52248.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/michaelgao/services/trackbacks/52248.html</trackback:ping><description><![CDATA[new 实现？<br>
1、调用 void * operator new(size_t size); <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
表示其返回的是一个未经处理（raw）的指针，指向未初始化的<clk><nobr id="clickeyekey4" style="border-bottom: 1px dotted #6600ff; text-decoration: underline; color: #6600ff; background-color: transparent;" onclick="return kwc(event,4)" target="_blank" oncontextmenu="return false;" onmouseover="kwE(event,4, this);" onmouseout="kwL(event,this)" onmousemove="kwM(4);">内存</nobr>。参数size_t确定分配多少内存。你能增加额外的参数重载函数operator new，但是第一个参数类型必须是size_t</clk><br>
2、调用类的构造函数。 <br>
在第一步，operator new是怎么申请内存的？ 是调用的 malloc来申请内存吗？<br>
<br>
<strong>operator new和delete函数的实现</strong><br>
<br>
下划线表示不一定准确，需要重新确认。<br>
<p>&nbsp;<u>&nbsp;&nbsp; operator new实际上总是以<a href="http://www.csai.cn/incsearch/search.asp?key=%B1%EA%D7%BC" target="_blank">标准</a><clk>的C malloc()完成，虽然并没有规定非得这么做不可。同样，operator delete也总是以<nobr id="clickeyekey7" style="border-bottom: 1px dotted #6600ff; text-decoration: underline; color: #6600ff; background-color: transparent;" onclick="return kwc(event,7)" target="_blank" oncontextmenu="return false;" onmouseover="kwE(event,7, this);" onmouseout="kwL(event,this)" onmousemove="kwM(7);">标准</nobr>得C free()来实现，不考虑异常处理的话他们类似下面的样子：</clk></u></p>
<p><font color="#aa5555">　　　　　extern void* operator new( size_t size )<br>
{<br>
&nbsp;&nbsp;&nbsp; if( size == 0 )<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; size = 1;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 这里保证像 new T[0] 这样得语句也是可行的<br>
&nbsp;&nbsp;&nbsp; <br>
&nbsp; 　　　　　&nbsp; void *last_alloc;<br>
&nbsp; 　　　　　&nbsp; while( !(last_alloc = malloc( size )) )<br>
&nbsp; 　　　　　&nbsp; {<br>
&nbsp;&nbsp;&nbsp; 　　　　　&nbsp;&nbsp;&nbsp; if( _new_handler )<br>
&nbsp;&nbsp;&nbsp; 　　　　　&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ( *_new_handler )();<br>
&nbsp;&nbsp;&nbsp; 　　　　　&nbsp;&nbsp;&nbsp; else<br>
&nbsp;&nbsp;&nbsp; 　　　　　&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 0;<br>
&nbsp; 　　　　　&nbsp; }<br>
&nbsp; 　　　　　&nbsp; return last_alloc;<br>
}</font></p>
<font color="#aa5555">　　　　　extern void operator delete( void *ptr )<br>
{<br>
&nbsp; 　　　　　&nbsp; if(ptr)&nbsp; // 从这里可以看出，删除一个空指针是<a href="http://www.csai.cn/incsearch/search.asp?key=%B0%B2%C8%AB" target="_blank">安全</a>的<br>
&nbsp; 　　　　　&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; free( (char*)ptr );<br>
} </font><br>
<br>
<br>
<div>&nbsp;</div>
<strong>new和malloc区别两个 &nbsp; <br>
&nbsp; &nbsp; <br>
&nbsp; 1 &nbsp; new是操作符 &nbsp; <br>
&nbsp; &nbsp; &nbsp; malloc是库函数 &nbsp; <br>
&nbsp; &nbsp; <br>
&nbsp; 2 &nbsp; new可以调用构造函数，malloc不可以 &nbsp; </strong><br>
<br>
<img src="http://www.cnblogs.com/michael-gao/aggbug/1214226.html?type=1" width="1" height="1"><br><br>
<div align="right"><a style="text-decoration: none;" href="http://michael-gao.cnblogs.com/" target="_blank">michalegao</a> 2008-06-05 11:43 <a href="http://www.cnblogs.com/michael-gao/archive/2008/06/05/1214226.html#Feedback" target="_blank" style="text-decoration: none;">发表评论</a></div>
<br>文章来源:<a href="http://www.cnblogs.com/michael-gao/archive/2008/06/05/1214226.html">http://www.cnblogs.com/michael-gao/archive/2008/06/05/1214226.html</a> <img src ="http://www.cppblog.com/michaelgao/aggbug/52248.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/michaelgao/" target="_blank">micheal's tech</a> 2008-06-05 15:59 <a href="http://www.cppblog.com/michaelgao/archive/2008/06/05/52248.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[导入]C++面试题--来自网上。</title><link>http://www.cppblog.com/michaelgao/archive/2008/06/05/52249.html</link><dc:creator>micheal's tech</dc:creator><author>micheal's tech</author><pubDate>Thu, 05 Jun 2008 07:59:00 GMT</pubDate><guid>http://www.cppblog.com/michaelgao/archive/2008/06/05/52249.html</guid><wfw:comment>http://www.cppblog.com/michaelgao/comments/52249.html</wfw:comment><comments>http://www.cppblog.com/michaelgao/archive/2008/06/05/52249.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/michaelgao/comments/commentRss/52249.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/michaelgao/services/trackbacks/52249.html</trackback:ping><description><![CDATA[1、new和malloc()有什么区别； <br>
a. new 是 C++ 中的东西，而 malloc 是 C 中的东东<br>
b. new 是操作符，而 malloc 是函数(?不记得是函数还是宏了)<br>
c. new 可以对变量初始化，调用构造函数，而 malloc 没有这个功能<br>
d. new 是异常安全的，分配失败可以捕获到 std::bad_alloc 异常<br>
<br>
2、ASSERT和VERIFY有什么区别； <br>
a. ASSERT 宏的作用在于检查表达式是否为假或为 NULL，如果为假则会引发异常，ASSERT 宏只在调试版本中才会有作用<br>
b. VERIFY 宏与 ASSERT 宏的 VERIFY 的不同在与 VERIFY 在发行版本中同样会起作用，但是使用 VERIFY 会导致非常不友好的用户界面<br>
<br>
3、模式对话框与非模式对话框有什么区别； <br>
a. 模式对话框总是独占的，而非模式对话框不是独占的<br>
<br>
4、SendMessage()与PostMessage()有什么区别； <br>
a. SendMessage() 会等到返回才往下走，而 PostMessage 则不管<br>
<br>
5、在继承类中，子类是如何构造的？又是如何析构的？ <br>
a. 子类构造：先调用基类的构造函数(按继续表顺序)，然后调用类成员的构造函数，最后调用执行自己的构造函数<br>
&nbsp; &nbsp;析构通常情况下是相反的<br>
<br>
6、什么是虚函数？ <br>
在 C++ 中，用 virtual 标识的函数<br>
<br>
7、什么是多态？ <br>
多态指发出同样的消息被不同类型的对象接收时导致完全不同的行为<br>
<br>
8、socket编程，如何处理阻塞？ <br>
a. 设置超时时间<br>
<br>
9、静态变量的作用是什么？静态成员变量有什么优缺点？ <br>
a. 控制存储方式<br>
b. 控制可见性与连接类型
<img src="http://www.cnblogs.com/michael-gao/aggbug/1214180.html?type=1" width="1" height="1"><br><br>
<div align="right"><a style="text-decoration: none;" href="http://michael-gao.cnblogs.com/" target="_blank">michalegao</a> 2008-06-05 10:55 <a href="http://www.cnblogs.com/michael-gao/archive/2008/06/05/1214180.html#Feedback" target="_blank" style="text-decoration: none;">发表评论</a></div>
<br>文章来源:<a href="http://www.cnblogs.com/michael-gao/archive/2008/06/05/1214180.html">http://www.cnblogs.com/michael-gao/archive/2008/06/05/1214180.html</a> <img src ="http://www.cppblog.com/michaelgao/aggbug/52249.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/michaelgao/" target="_blank">micheal's tech</a> 2008-06-05 15:59 <a href="http://www.cppblog.com/michaelgao/archive/2008/06/05/52249.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>