﻿<?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++博客-Chosen</title><link>http://www.cppblog.com/Chosen/</link><description /><language>zh-cn</language><lastBuildDate>Sun, 05 Apr 2026 15:18:16 GMT</lastBuildDate><pubDate>Sun, 05 Apr 2026 15:18:16 GMT</pubDate><ttl>60</ttl><item><title>C++实现简单的线程池</title><link>http://www.cppblog.com/Chosen/archive/2013/10/07/203568.html</link><dc:creator>Choice</dc:creator><author>Choice</author><pubDate>Mon, 07 Oct 2013 11:22:00 GMT</pubDate><guid>http://www.cppblog.com/Chosen/archive/2013/10/07/203568.html</guid><wfw:comment>http://www.cppblog.com/Chosen/comments/203568.html</wfw:comment><comments>http://www.cppblog.com/Chosen/archive/2013/10/07/203568.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Chosen/comments/commentRss/203568.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Chosen/services/trackbacks/203568.html</trackback:ping><description><![CDATA[<p style="margin:0in;font-family:SimSun;font-size:10.5pt"><strong>线程池编程简介：</strong></p>  <p style="margin:0in;font-size:10.5pt"><span style="font-family:Calibri">&nbsp;&nbsp;&nbsp; </span><span style="font-family:SimSun">在我们的服务端的程序中运用了大量关于池的概念，线程池、连接池、内存池、对象池等等。使用池的概念后可以高效利用服务器端的资源，比如没有大量的线程在系统中进行上下文的切换，一个数据库连接池，也只需要维护一定里的连接，而不是占用很多数据库连接资源。同时它们也避免了一些耗时的操作，比如创建一个线程，申请一个数据库连接，而且可能就只使用那么一次，然后就立刻释放刚申请的资源，效率很低。</span></p>  <p style="margin:0in;font-size:10.5pt"><span style="font-family:Calibri">&nbsp;&nbsp;&nbsp; </span><span style="font-family:SimSun">在我的上一篇</span><span style="font-family: Calibri">blog</span><span style="font-family:SimSun">中已经实现一个线程基类了，在这里我们只需要实现一个线程池类</span><span style="font-family:Calibri">ThreadPool</span><span style="font-family: SimSun">和该线程池调度的工作线程类</span><span style="font-family:Calibri">WorkThread</span><span style="font-family:SimSun">即可，而且</span><span style="font-family:Calibri">WorkThread</span><span style="font-family: SimSun">是继承自</span><span style="font-family:Calibri">Thread</span><span style="font-family:SimSun">类的。</span></p>  <p style="margin:0in;font-family:SimSun;font-size:10.5pt">&nbsp;</p>  <p style="margin:0in;font-family:SimSun;font-size:10.5pt"><strong>实现思路：</strong></p>  <p style="margin:0in;font-size:10.5pt"><span style="font-family:Calibri">&nbsp;&nbsp;&nbsp; </span><span style="font-family:SimSun">一个简单的线程池的实现思路一般如下：</span></p>  <ol type="1" style="margin-left: 0.375in; direction: ltr; unicode-bidi: embed; margin-top: 0in; margin-bottom: 0in; font-family: Calibri; font-size: 10.5pt;">  <li value="1" style="margin-top:0;margin-bottom:0;vertical-align:middle"><span style="font-family: SimSun; font-size: 10.5pt;">在</span><span style="font-size: 10.5pt;">ThreadPool</span><span style="font-family: SimSun; font-size: 10.5pt;">中创建多个线程</span><span style="font-size: 10.5pt;">(WorkThreadk</span><span style="font-family: SimSun; font-size: 10.5pt;">对象</span><span style="font-size: 10.5pt;">)</span><span style="font-family: SimSun; font-size: 10.5pt;">，每个线程均处于阻塞状态，等待任务的到来</span></li> </ol>  <ol type="1" style="margin-left: 0.375in; direction: ltr; unicode-bidi: embed; margin-top: 0in; margin-bottom: 0in; font-family: Calibri; font-size: 10.5pt;">  <li value="2" style="margin-top:0;margin-bottom:0;vertical-align:middle"><span style="font-size: 10.5pt;">ThreadPool</span><span style="font-family: SimSun; font-size: 10.5pt;">提供一个提交任务的接口，如</span><span style="font-size: 10.5pt;">post_job(ProcCallback      func, void* data); post_job</span><span style="font-family: SimSun; font-size: 10.5pt;">后会立即返回，不会阻塞</span></li>  <li style="margin-top:0;margin-bottom:0;vertical-align:middle"><span style="font-size: 10.5pt;">ThreadPool</span><span style="font-family:SimSun;font-size:10.5pt">维护一个空闲线程队列，当客户程序调用</span><span style="font-size: 10.5pt;">post_job()</span><span style="font-family:SimSun;font-size:10.5pt">后，如果空闲队列中有空闲线程，则取出一个线程句柄，并设置任务再给出新任务通知事件即可，处理等待的线程捕捉到事件信号后便开始执行任务，执行完后将该线程句柄重新</span><span style="font-size: 10.5pt;">push</span><span style="font-family:SimSun;font-size:10.5pt">到空闲线程队列中</span></li>  <li style="margin-top:0;margin-bottom:0;vertical-align:middle"><span style="font-family:SimSun;font-size:10.5pt">该线程池采用回调函数方式</span></li> </ol>  <p style="margin:0in;font-size:10.5pt"><span style="font-family:SimSun">首先我们实现一个</span><span style="font-family:Calibri">WorkThread</span><span style="font-family: SimSun;">类：<br /></span></p><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #008080; ">&nbsp;1</span>&nbsp;typedef&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;(APR_THREAD_FUNC&nbsp;*ProcCallBack)(<span style="color: #0000FF; ">void</span>*);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">回调函数指针<br /></span><span style="color: #008080; ">&nbsp;2</span>&nbsp;<span style="color: #008000; "></span><span style="color: #008000; ">//</span><span style="color: #008000; ">由线程池调度的工作线程</span><span style="color: #008000; "><br /></span><span style="color: #008080; ">&nbsp;3</span>&nbsp;<span style="color: #008000; "></span><span style="color: #0000FF; ">class</span>&nbsp;WorkThread&nbsp;:&nbsp;<span style="color: #0000FF; ">public</span>&nbsp;Thread &nbsp; &nbsp; &nbsp;//Thread类的实现可参考我上一篇的blog: 《C++封装一个简单的线程类》<br /><span style="color: #008080; ">&nbsp;4</span>&nbsp;{<br /><span style="color: #008080; ">&nbsp;5</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;friend&nbsp;<span style="color: #0000FF; ">class</span>&nbsp;ThreadPool;<br /><span style="color: #008080; ">&nbsp;6</span>&nbsp;<span style="color: #0000FF; ">public</span>:<br /><span style="color: #008080; ">&nbsp;7</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;WorkThread(ThreadPool*&nbsp;pthr_pool)<br /><span style="color: #008080; ">&nbsp;8</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br /><span style="color: #008080; ">&nbsp;9</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;thr_pool_&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;pthr_pool;<br /><span style="color: #008080; ">10</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cb_func_&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;NULL;<br /><span style="color: #008080; ">11</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;param_&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;NULL;<br /><span style="color: #008080; ">12</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br /><span style="color: #008080; ">13</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">virtual</span>&nbsp;~WorkThread(){}<br /><span style="color: #008080; ">14</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;&nbsp;&nbsp;&nbsp;set_job(ProcCallBack&nbsp;func,&nbsp;<span style="color: #0000FF; ">void</span>*&nbsp;param)<br /><span style="color: #008080; ">15</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br /><span style="color: #008080; ">16</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cb_func_&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;func;<br /><span style="color: #008080; ">17</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;param_&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;param;<br /><span style="color: #008080; ">18</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;notify();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">通知有新的任务</span><span style="color: #008000; "><br /></span><span style="color: #008080; ">19</span>&nbsp;<span style="color: #008000; "></span>&nbsp;&nbsp;&nbsp;&nbsp;}<br /><span style="color: #008080; ">20</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">实现Thread的run方法，并调用用户指定的函数</span><span style="color: #008000; "><br /></span><span style="color: #008080; ">21</span>&nbsp;<span style="color: #008000; "></span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">virtual</span>&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;run()<br /><span style="color: #008080; ">22</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br /><span style="color: #008080; ">23</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(cb_func_)<br /><span style="color: #008080; ">24</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cb_func_(param_);<br /><span style="color: #008080; ">25</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br /><span style="color: #008080; ">26</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">reset&nbsp;callback&nbsp;function&nbsp;pointer</span><span style="color: #008000; "><br /></span><span style="color: #008080; ">27</span>&nbsp;<span style="color: #008000; "></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cb_func_&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;NULL;<br /><span style="color: #008080; ">28</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;param_&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;NULL;<br /><span style="color: #008080; ">29</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br /><span style="color: #008080; ">30</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">执行完任务，将该线程句柄移到线程池空闲队列</span><span style="color: #008000; "><br /></span><span style="color: #008080; ">31</span>&nbsp;<span style="color: #008000; "></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;thr_pool_-&gt;move_to_idle_que(<span style="color: #0000FF; ">this</span>);<br /><span style="color: #008080; ">32</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br /><span style="color: #008080; ">33</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br /><span style="color: #008080; ">34</span>&nbsp;<span style="color: #0000FF; ">private</span>:<br /><span style="color: #008080; ">35</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ThreadPool*&nbsp;&nbsp;&nbsp;&nbsp;thr_pool_;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">线程池指针</span><span style="color: #008000; "><br /></span><span style="color: #008080; ">36</span>&nbsp;<span style="color: #008000; "></span>&nbsp;&nbsp;&nbsp;&nbsp;ProcCallBack&nbsp;&nbsp;&nbsp;&nbsp;cb_func_;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">回调函数地址</span><span style="color: #008000; "><br /></span><span style="color: #008080; ">37</span>&nbsp;<span style="color: #008000; "></span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">void</span>*&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;param_; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008000; ">//</span><span style="color: #008000; ">回调函数参数</span><span style="color: #008000; "><br /></span><span style="color: #008080; ">38</span>&nbsp;<span style="color: #008000; "></span>};</div><p style="margin:0in;font-size:10.5pt"><span style="font-family:SimSun" lang="zh-CN">该</span><span style="font-family:Calibri" lang="en-US">WorkThread</span><span style="font-family:SimSun" lang="zh-CN">中，有一个回调函数指针和参数，当有新任务时，会在</span><span style="font-family:Calibri" lang="en-US">run()</span><span style="font-family:
SimSun" lang="zh-CN">中被调用，执行完后会将该线程移动到空闲线程队列，等待下一次任务的提交。</span></p><p style="margin:0in;font-size:10.5pt"><span style="font-family:Calibri" lang="en-US">ThreadPool</span><span style="font-family:SimSun" lang="zh-CN">类定义如下：</span></p><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #008080; ">&nbsp;1</span>&nbsp;<span style="color: #0000FF; ">class</span>&nbsp;ThreadPool<br /><span style="color: #008080; ">&nbsp;2</span>&nbsp;{<br /><span style="color: #008080; ">&nbsp;3</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;friend&nbsp;<span style="color: #0000FF; ">class</span>&nbsp;WorkThread;<br /><span style="color: #008080; ">&nbsp;4</span>&nbsp;<span style="color: #0000FF; ">public</span>:<br /><span style="color: #008080; ">&nbsp;5</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ThreadPool();<br /><span style="color: #008080; ">&nbsp;6</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">virtual</span>&nbsp;~ThreadPool();<br /><span style="color: #008080; ">&nbsp;7</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;&nbsp;&nbsp;&nbsp;start_thread_pool(size_t&nbsp;thread_num&nbsp;=&nbsp;5);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">启动thread_num个线程</span><span style="color: #008000; "><br /></span><span style="color: #008080; ">&nbsp;8</span>&nbsp;<span style="color: #008000; "></span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;&nbsp;&nbsp;&nbsp;stop_thread_pool();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">线束线程池</span><span style="color: #008000; "><br /></span><span style="color: #008080; ">&nbsp;9</span>&nbsp;<span style="color: #008000; "></span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;&nbsp;&nbsp;&nbsp;destroy();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">销毁线程池所申请的资源</span><span style="color: #008000; "><br /></span><span style="color: #008080; ">10</span>&nbsp;<span style="color: #008000; "></span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;&nbsp;&nbsp;&nbsp;post_job(ProcCallBack&nbsp;func,&nbsp;<span style="color: #0000FF; ">void</span>*&nbsp;data);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">提交任务接口，传入回调函数地址和参数</span><span style="color: #008000; "><br /></span><span style="color: #008080; ">11</span>&nbsp;<span style="color: #008000; "></span><br /><span style="color: #008080; ">12</span>&nbsp;<span style="color: #0000FF; ">protected</span>:<br /><span style="color: #008080; ">13</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;WorkThread*&nbsp;&nbsp;&nbsp;&nbsp;get_idle_thread();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">从获得空闲队列中取得一个线程句柄</span><span style="color: #008000; "><br /></span><span style="color: #008080; ">14</span>&nbsp;<span style="color: #008000; "></span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;append_idle_thread(WorkThread*&nbsp;pthread);&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">加入到thread_vec_和idl_que_中</span><span style="color: #008000; "><br /></span><span style="color: #008080; ">15</span>&nbsp;<span style="color: #008000; "></span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;move_to_idle_que(WorkThread*&nbsp;idlethread);&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">将线程句柄加入到idle_que_中</span><span style="color: #008000; "><br /></span><span style="color: #008080; ">16</span>&nbsp;<span style="color: #008000; "></span><br /><span style="color: #008080; ">17</span>&nbsp;<span style="color: #0000FF; ">private</span>:<br /><span style="color: #008080; ">18</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;size_t&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;thr_num_;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">线程数目</span><span style="color: #008000; "><br /></span><span style="color: #008080; ">19</span>&nbsp;<span style="color: #008000; "></span>&nbsp;&nbsp;&nbsp;&nbsp;vector&lt;WorkThread*&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;thr_vec_;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">线程句柄集合</span><span style="color: #008000; "><br /></span><span style="color: #008080; ">20</span>&nbsp;<span style="color: #008000; "></span>&nbsp;&nbsp;&nbsp;&nbsp;BlockQueue&lt;WorkThread*&gt;&nbsp;&nbsp;&nbsp;&nbsp;idle_que_; &nbsp; &nbsp; <span style="color: #008000; ">//</span><span style="color: #008000; ">空闲线程队列</span><span style="color: #008000; "><br /></span><span style="color: #008080; ">21</span>&nbsp;<span style="color: #008000; "></span><br /><span style="color: #008080; ">22</span>&nbsp;<span style="color: #0000FF; ">private</span>:<br /><span style="color: #008080; ">23</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;not&nbsp;implement</span><span style="color: #008000; "><br /></span><span style="color: #008080; ">24</span>&nbsp;<span style="color: #008000; "></span>&nbsp;&nbsp;&nbsp;&nbsp;ThreadPool(<span style="color: #0000FF; ">const</span>&nbsp;ThreadPool&amp;&nbsp;);<br /><span style="color: #008080; ">25</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ThreadPool&amp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">operator</span>=(<span style="color: #0000FF; ">const</span>&nbsp;ThreadPool&amp;&nbsp;);<br /><span style="color: #008080; ">26</span>&nbsp;};</div><div>&nbsp; &nbsp; &nbsp; 线程池实现的关键是如何创建多个线程，并且当任务来临时可以从线程池中取一个线程（也就是去得到其中一个线程的指针），然后提交任务并执行。还有一点就是当任务执行完后，应该将该线程句柄重新加入到空闲线程队列，所以我们将ThreadPool的指针传入给了WorkThread，thr_pool_最后可以调用move_to_idle_que(this)来将该线程句柄移到空闲队列中。</div><div>ThreadPool中一些关键代码的实现：</div><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #008080; ">&nbsp;1</span>&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;ThreadPool::start_thread_pool(size_t&nbsp;thread_num)<br /><span style="color: #008080; ">&nbsp;2</span>&nbsp;{<br /><span style="color: #008080; ">&nbsp;3</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;assert(thread_num&nbsp;!=&nbsp;0);<br /><span style="color: #008080; ">&nbsp;4</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;thr_num_&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;thread_num;<br /><span style="color: #008080; ">&nbsp;5</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;&nbsp;&nbsp;&nbsp;ret&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;0;<br /><span style="color: #008080; ">&nbsp;6</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">for</span>&nbsp;(size_t&nbsp;i&nbsp;=&nbsp;0;&nbsp;i&nbsp;&lt;&nbsp;thr_num_;&nbsp;++i)<br /><span style="color: #008080; ">&nbsp;7</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br /><span style="color: #008080; ">&nbsp;8</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;WorkThread*&nbsp;&nbsp;&nbsp;&nbsp;pthr&nbsp;=&nbsp;<span style="color: #0000FF; ">new</span>&nbsp;WorkThread(<span style="color: #0000FF; ">this</span>);<br /><span style="color: #008080; ">&nbsp;9</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pthr-&gt;set_thread_id(i);<br /><span style="color: #008080; ">10</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;((ret&nbsp;=&nbsp;pthr-&gt;start())&nbsp;!=&nbsp;0)<br /><span style="color: #008080; ">11</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br /><span style="color: #008080; ">12</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf("start_thread_pool:&nbsp;failed&nbsp;when&nbsp;create&nbsp;a&nbsp;work&nbsp;thread:&nbsp;%d\n",&nbsp;i);<br /><span style="color: #008080; ">13</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;delete&nbsp;pthr;<br /><span style="color: #008080; ">14</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;i;<br /><span style="color: #008080; ">15</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br /><span style="color: #008080; ">16</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;append_idle_thread(pthr);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br /><span style="color: #008080; ">17</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br /><span style="color: #008080; ">18</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;thr_num_;<br /><span style="color: #008080; ">19</span>&nbsp;}<br /><span style="color: #008080; ">20</span>&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;ThreadPool::stop_thread_pool()<br /><span style="color: #008080; ">21</span>&nbsp;{<br /><span style="color: #008080; ">22</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">for</span>&nbsp;(size_t&nbsp;i&nbsp;=&nbsp;0;&nbsp;i&nbsp;&lt;&nbsp;thr_vec_.size();&nbsp;++i)<br /><span style="color: #008080; ">23</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br /><span style="color: #008080; ">24</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;WorkThread*&nbsp;pthr&nbsp;=&nbsp;thr_vec_[i];<br /><span style="color: #008080; ">25</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pthr-&gt;join();<br /><span style="color: #008080; ">26</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;delete&nbsp;pthr;<br /><span style="color: #008080; ">27</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br /><span style="color: #008080; ">28</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;thr_vec_.clear();<br /><span style="color: #008080; ">29</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;idle_que_.clear();<br /><span style="color: #008080; ">30</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;0;<br /><span style="color: #008080; ">31</span>&nbsp;}<br /><span style="color: #008080; ">32</span>&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;ThreadPool::destroy()<br /><span style="color: #008080; ">33</span>&nbsp;{<br /><span style="color: #008080; ">34</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;stop_thread_pool();<br /><span style="color: #008080; ">35</span>&nbsp;}<br /><span style="color: #008080; ">36</span>&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;ThreadPool::append_idle_thread(WorkThread*&nbsp;pthread)<br /><span style="color: #008080; ">37</span>&nbsp;{<br /><span style="color: #008080; ">38</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;thr_vec_.push_back(pthread);<br /><span style="color: #008080; ">39</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;idle_que_.push(pthread);<br /><span style="color: #008080; ">40</span>&nbsp;}<br /><span style="color: #008080; ">41</span>&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;ThreadPool::move_to_idle_que(WorkThread*&nbsp;idlethread)<br /><span style="color: #008080; ">42</span>&nbsp;{<br /><span style="color: #008080; ">43</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;idle_que_.push(idlethread);<br /><span style="color: #008080; ">44</span>&nbsp;}<br /><span style="color: #008080; ">45</span>&nbsp;WorkThread*&nbsp;ThreadPool::get_idle_thread()<br /><span style="color: #008080; ">46</span>&nbsp;{<br /><span style="color: #008080; ">47</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;WorkThread*&nbsp;&nbsp;&nbsp;&nbsp;pthr&nbsp;=&nbsp;NULL;<br /><span style="color: #008080; ">48</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(!idle_que_.empty())<br /><span style="color: #008080; ">49</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pthr&nbsp;=&nbsp;idle_que_.take();<br /><span style="color: #008080; ">50</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;pthr;<br /><span style="color: #008080; ">51</span>&nbsp;}<br /><span style="color: #008080; ">52</span>&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;ThreadPool::post_job(ProcCallBack&nbsp;func,&nbsp;<span style="color: #0000FF; ">void</span>*&nbsp;data)<br /><span style="color: #008080; ">53</span>&nbsp;{<br /><span style="color: #008080; ">54</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;assert(func&nbsp;!=&nbsp;NULL);<br /><span style="color: #008080; ">55</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;WorkThread*&nbsp;pthr&nbsp;=&nbsp;get_idle_thread();<br /><span style="color: #008080; ">56</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">while</span>&nbsp;(pthr&nbsp;==&nbsp;NULL)<br /><span style="color: #008080; ">57</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br /><span style="color: #008080; ">58</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;apr_sleep(500000);<br /><span style="color: #008080; ">59</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pthr&nbsp;=&nbsp;get_idle_thread();<br /><span style="color: #008080; ">60</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br /><span style="color: #008080; ">61</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pthr-&gt;set_job(func,&nbsp;data);<br /><span style="color: #008080; ">62</span>&nbsp;}</div><div><font face="SimSun">ThreadPool中的BlockQueue&lt;WorkThread*&gt; 也就是一个线程安全的队列，即对std::deque做了一个包装，在插入和取出元素时加了一个读写锁。</font></div><p style="margin: 0in;"><br /></p><div><strong>使用示例：</strong></div><div>//任务执行函数，必须是ProcCallback类型</div><div>void count(void* param)</div><div>{</div><div><span style="white-space:pre">	</span>// do some your work, like:&nbsp;</div><div><span style="white-space:pre">	</span>int* pi = static_cast&lt;int*&gt;(param);</div><div><span style="white-space:pre">	</span>int val = *pi + 1;</div><div><span style="white-space:pre">	</span>printf("val=%d\n", val);</div><div><span style="white-space:pre">	</span>pelete pi;</div><div>}</div><div></div><div>//程序中使用如下：</div><div>ThreadPool* ptp = new ThreadPool();</div><div>ptp-&gt;start_thread_pool(3);<span style="white-space:pre">		</span>//启动3 个线程</div><div>ptp-&gt;post_job(count, new int(1));<span style="white-space:pre">		</span>//提交任务</div><div>ptp-&gt;post_job(count, new int(2));</div><div>ptp-&gt;post_job(count, new int(3));</div><div>//程序线束时</div><div>ptp-&gt;stop_thread_pool();</div><div>其实count()函数就是我们的业务实现代码，有任务时，可以提交给线程池去执行。</div><div></div><div><strong>结尾：</strong></div><div>&nbsp; &nbsp; 其实实现一个线程池或其它什么池并不难，当然线程安全和效率还是要从多写代码的经验中获取。像这个线程池也就是基于预创多个建线程，保保存好它们的线程句柄，当有新任务时取一个线程执行即可，执行完后一定要归还到空闲线程队列中，当然我们可以在线程池中增加一个任务队列，因为当post_job()时，若当时没有空闲线程，有两种方案，一是等待有空闲线程，二是加入到任务队列，当WorkThread线程执行完一个任务后，从任务队列中取一个任务继续执行即可，不会阻塞在post_job()中。</div><div>&nbsp; 另外，我们可以封装一些线程安全的队列和map什么的，这样在程序中就不用担心创建一个多线程共享的队列时，还必须创建一个锁，挺麻烦的，比如上面的BlockQueue&lt;Type&gt;直接拿来用就行了。</div><div></div><img src ="http://www.cppblog.com/Chosen/aggbug/203568.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Chosen/" target="_blank">Choice</a> 2013-10-07 19:22 <a href="http://www.cppblog.com/Chosen/archive/2013/10/07/203568.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C++封装一个简单的线程类</title><link>http://www.cppblog.com/Chosen/archive/2013/10/07/203567.html</link><dc:creator>Choice</dc:creator><author>Choice</author><pubDate>Mon, 07 Oct 2013 10:12:00 GMT</pubDate><guid>http://www.cppblog.com/Chosen/archive/2013/10/07/203567.html</guid><wfw:comment>http://www.cppblog.com/Chosen/comments/203567.html</wfw:comment><comments>http://www.cppblog.com/Chosen/archive/2013/10/07/203567.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Chosen/comments/commentRss/203567.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Chosen/services/trackbacks/203567.html</trackback:ping><description><![CDATA[<p style="margin:0in;font-family:SimSun;font-size:10.5pt"><strong>多线程编程简介：</strong></p>  <p style="margin:0in;font-size:10.5pt"><span style="font-family:Calibri">&nbsp;&nbsp;&nbsp; </span><span style="font-family:SimSun">大家在编程时，经常需要在程序中启动一个或多个线程来处理任务，而如果每次都是去调用系统创建线程的</span><span style="font-family:Calibri">API</span><span style="font-family:SimSun">函数来创建，代码量虽不多，但线程的创建和业务逻辑代码就揉在一起了，且创建多个线程的时候，有大量的重复代码，不便于维护。若我们把创建线程和销毁线程的这些共同的代码封装到一个类中，这样我们可以更专注业务逻辑的实现，在其它地方直接拿来用就行，程序也便于维护和扩展。而且这样的话即使程序所使用的线程库更换了，但线程类提供的接口没变，所以我们的业务逻辑代码也不用任何的改动。</span></p>  <p style="margin:0in;font-size:10.5pt"><span style="font-family:Calibri">&nbsp;&nbsp;&nbsp; </span><span style="font-family:SimSun">创建一个线程也无非就是调用系统线程</span><span style="font-family:Calibri">API</span><span style="font-family:SimSun">或第三方库的</span><span style="font-family:Calibri">API</span><span style="font-family:SimSun">，然后传入线程函数地址和线程运行所需要的参数即可，所以我们需要将此部分代码抽象出来，并提供使用接口即可。</span></p>  <p style="margin:0in;font-family:SimSun;font-size:10.5pt">&nbsp;</p>  <p style="margin:0in;font-size:10.5pt"><strong><span style="font-family:SimSun">一个线程基类</span><span style="font-family:Calibri">Thread</span></strong></p>  <p style="margin:0in;font-size:10.5pt"><span style="font-family:Calibri">&nbsp;&nbsp;&nbsp; </span><span style="font-family:SimSun">这里我们使用的是</span><span style="font-family: Calibri">Apache</span><span style="font-family:SimSun">提供的</span><span style="font-family:Calibri">apr</span><span style="font-family:SimSun">库，该库具有跨平台性，当然不管使用什么库，我们提供的接口都是一样的，且线程创建和销毁的逻辑是一样的。代码：</span></p>  <div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #008080; ">&nbsp;1</span>&nbsp;<span style="color: #0000FF; ">class</span>&nbsp;Thread<br /><span style="color: #008080; ">&nbsp;2</span>&nbsp;{<br /><span style="color: #008080; ">&nbsp;3</span>&nbsp;<span style="color: #0000FF; ">public</span>:<br /><span style="color: #008080; ">&nbsp;4</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Thread(<span style="color: #0000FF; ">bool</span>&nbsp;bDetach&nbsp;=&nbsp;<span style="color: #0000FF; ">true</span>);<br /><span style="color: #008080; ">&nbsp;5</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">virtual</span>&nbsp;~Thread();<br /><span style="color: #008080; ">&nbsp;6</span>&nbsp;<br /><span style="color: #008080; ">&nbsp;7</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">virtual</span>&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;run()&nbsp;=&nbsp;0; &nbsp; &nbsp; &nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">业务接口</span><span style="color: #008000; "><br /></span><span style="color: #008080; ">&nbsp;8</span>&nbsp;<span style="color: #008000; "></span><br /><span style="color: #008080; ">&nbsp;9</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">int</span>&nbsp; &nbsp; &nbsp; &nbsp;start();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">启动线程</span><span style="color: #008000; "><br /></span><span style="color: #008080; ">10</span>&nbsp;<span style="color: #008000; "></span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">int</span>&nbsp; &nbsp; &nbsp; join();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">等待线程线束</span><span style="color: #008000; "><br /></span><span style="color: #008080; ">11</span>&nbsp;<span style="color: #008000; "></span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;&nbsp;&nbsp;&nbsp;destroy();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">销毁线程所申请的资源<br /></span><span style="color: #008080; ">12</span>&nbsp;<span style="color: #008000; "><br /></span><span style="color: #008080; ">13</span>&nbsp;<span style="color: #008000; ">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;attribute&nbsp;functions</span><span style="color: #008000; "><br /></span><span style="color: #008080; ">14</span>&nbsp;<span style="color: #008000; "></span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">int</span>&nbsp; &nbsp; &nbsp; get_thread_id()&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;thr_id_;&nbsp;}<br /><span style="color: #008080; ">15</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;&nbsp;&nbsp;&nbsp;set_thread_id(unsigned&nbsp;<span style="color: #0000FF; ">long</span>&nbsp;thrId)&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;thr_id_&nbsp;=&nbsp;thrId;&nbsp;}<br /><span style="color: #008080; ">16</span>&nbsp;<br /><span style="color: #008080; ">17</span>&nbsp;<span style="color: #0000FF; ">protected</span>:<br /><span style="color: #008080; ">18</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">static</span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">void</span>*&nbsp;__stdcall&nbsp;thread_proc(apr_thread_t*&nbsp;th,&nbsp;<span style="color: #0000FF; ">void</span>*&nbsp;data);<br /><span style="color: #008080; ">19</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;&nbsp;&nbsp;&nbsp;notify() { cond_.signal(); }<br /><span style="color: #008080; ">20</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">bool</span>&nbsp;&nbsp;&nbsp;&nbsp;check_interrupt()&nbsp;{&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;bExit_;&nbsp;}<br /><span style="color: #008080; ">21</span>&nbsp;<br /><span style="color: #008080; ">22</span>&nbsp;<span style="color: #0000FF; ">private</span>:<br /><span style="color: #008080; ">23</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;size_t&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;thr_id_;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">线程ID</span><span style="color: #008000; "><br /></span><span style="color: #008080; ">24</span>&nbsp;<span style="color: #008000; "></span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">bool</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bExit_;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">线程是否要退出标志</span><span style="color: #008000; "><br /></span><span style="color: #008080; ">25</span>&nbsp;<span style="color: #008000; "></span><br /><span style="color: #008080; ">26</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;apr_thread_t*&nbsp;&nbsp;&nbsp;&nbsp;thr_;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">线程句柄</span><span style="color: #008000; "><br /></span><span style="color: #008080; ">27</span>&nbsp;<span style="color: #008000; "></span>&nbsp;&nbsp;&nbsp;&nbsp;Condition&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cond_;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">线程函数中等待任务的条件变量</span><span style="color: #008000; "><br /></span><span style="color: #008080; ">28</span>&nbsp;<span style="color: #008000; "></span>&nbsp;&nbsp;&nbsp;&nbsp;<br /><span style="color: #008080; ">29</span>&nbsp;<span style="color: #0000FF; ">private</span>:<br /><span style="color: #008080; ">30</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">not&nbsp;implement</span><span style="color: #008000; "><br /></span><span style="color: #008080; ">31</span>&nbsp;<span style="color: #008000; "></span>&nbsp;&nbsp;&nbsp;&nbsp;Thread(<span style="color: #0000FF; ">const</span>&nbsp;Thread&amp;&nbsp;);<br /><span style="color: #008080; ">32</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Thread&amp;&nbsp;<span style="color: #0000FF; ">operator</span>=(<span style="color: #0000FF; ">const</span>&nbsp;Thread&amp;&nbsp;);<br /><span style="color: #008080; ">33</span>&nbsp;};</div>  <p style="margin:0in;font-family:SimSun;font-size:10.5pt">一些说明：</p>  <ol type="1" style="margin-left: 0.375in; direction: ltr; unicode-bidi: embed; margin-top: 0in; margin-bottom: 0in; font-family: Calibri; font-size: 10.5pt;">  <li value="1" style="margin-top:0;margin-bottom:0;vertical-align:middle"><span style="font-family: SimSun; font-size: 10.5pt;">我们在</span><span style="font-size: 10.5pt;">start()</span><span style="font-family: SimSun; font-size: 10.5pt;">方法中调用</span><span style="font-size: 10.5pt;">apr</span><span style="font-family: SimSun; font-size: 10.5pt;">库提供的线程</span><span style="font-size: 10.5pt;">API</span><span style="font-family: SimSun; font-size: 10.5pt;">创建一个线程：</span><span style="font-size: 10.5pt;">      apr_thread_create()</span><span style="font-family: SimSun; font-size: 10.5pt;">，并将线程函数</span><span style="font-size: 10.5pt;">thread_proc()</span><span style="font-family: SimSun; font-size: 10.5pt;">和</span><span style="font-size: 10.5pt;">Thread*</span><span style="font-family: SimSun; font-size: 10.5pt;">为线程函数参数传入</span><span style="font-size: 10.5pt;">apr_thread_create()</span><span style="font-family: SimSun; font-size: 10.5pt;">即可，具体代码在后面贴出。</span></li>  <li style="margin-top:0;margin-bottom:0;vertical-align:middle"><span style="font-size: 10.5pt;">J</span><span style="font-family:SimSun;font-size:10.5pt">oin()</span><span style="font-family:SimSun;font-size:10.5pt">函数用于等待线束线程，而</span><span style="font-family:SimSun;font-size:10.5pt">destroy() </span><span style="font-family:SimSun;font-size:10.5pt">则是用于显示销毁该线程所占用的资源。</span></li>  <li style="margin-top:0;margin-bottom:0;vertical-align:middle"><span style="font-family:SimSun;font-size:10.5pt">线程基类有一个纯虚函数</span><span style="font-size: 10.5pt;">run()</span><span style="font-family:SimSun;font-size:10.5pt">，即应用线程继承</span><span style="font-size: 10.5pt;">Thread</span><span style="font-family:SimSun;font-size:10.5pt">类后必须实现</span><span style="font-size: 10.5pt;">run()</span><span style="font-family:SimSun;font-size:10.5pt">函数，即实现程序的业务逻辑</span></li>  <li style="margin-top:0;margin-bottom:0;vertical-align:middle"><span style="font-family:SimSun;font-size:10.5pt">在</span><span style="font-size: 10.5pt;">start()</span><span style="font-family:SimSun;font-size:10.5pt">创建完线程后系统便在某一时刻开始执行</span><span style="font-size: 10.5pt;">thread_proc()</span><span style="font-family:SimSun;font-size:10.5pt">方法，我们在该方法中会调用</span><span style="font-size: 10.5pt;">run()</span><span style="font-family:SimSun;font-size:10.5pt">函数，由于多态性，也就会调用应用程序多实现的</span><span style="font-size: 10.5pt;">run()</span><span style="font-family:SimSun;font-size:10.5pt">函数了<br /></span></li> </ol>  <p style="margin:0in;font-family:SimSun;font-size:10.5pt">具体实现(Thread.cpp)：</p>  <div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #008080; ">&nbsp;1</span>&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;&nbsp;&nbsp;&nbsp;Thread::start()<br /><span style="color: #008080; ">&nbsp;2</span>&nbsp;{<br /><span style="color: #008080; ">&nbsp;3</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;apr_status_t&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rv;<br /><span style="color: #008080; ">&nbsp;4</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;apr_threadattr_t*&nbsp;&nbsp;&nbsp;&nbsp;thrattr&nbsp;=&nbsp;NULL;&nbsp;&nbsp;&nbsp;&nbsp;<br /><span style="color: #008080; ">&nbsp;5</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;apr_threadattr_create(&amp;thrattr,&nbsp;g_mpool);<br /><span style="color: #008080; ">&nbsp;6</span>&nbsp;<br /><span style="color: #008080; ">&nbsp;7</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">创建一个线程</span><span style="color: #008000; "><br /></span><span style="color: #008080; ">&nbsp;8</span>&nbsp;<span style="color: #008000; "></span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;((rv&nbsp;=&nbsp;apr_thread_create(&amp;thr_,&nbsp;thrattr,&nbsp;Thread::thread_proc,&nbsp;<span style="color: #0000FF; ">this</span>,&nbsp;g_mpool))&nbsp;!=&nbsp;APR_SUCCESS)<br /><span style="color: #008080; ">&nbsp;9</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br /><span style="color: #008080; ">10</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;set_error_code(rv);<br /><span style="color: #008080; ">11</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">char</span>&nbsp;errbuf[512];<br /><span style="color: #008080; ">12</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;apr_strerror(rv,&nbsp;errbuf,&nbsp;<span style="color: #0000FF; ">sizeof</span>(errbuf));<br /><span style="color: #008080; ">13</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;log2DebugView("Thread:&nbsp;failed&nbsp;create&nbsp;a&nbsp;thread:&nbsp;[%d][%s]\n",&nbsp;rv,&nbsp;errbuf);<br /><span style="color: #008080; ">14</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;rv;<br /><span style="color: #008080; ">15</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br /><span style="color: #008080; ">16</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;apr_sleep(100000);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">ensure&nbsp;the&nbsp;thead_proc&nbsp;is&nbsp;running</span><span style="color: #008000; "><br /></span><span style="color: #008080; ">17</span>&nbsp;<span style="color: #008000; "></span><br /><span style="color: #008080; ">18</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;rv;<br /><span style="color: #008080; ">19</span>&nbsp;}<br /><span style="color: #008080; ">20</span>&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">等待线束线程</span><span style="color: #008000; "><br /></span><span style="color: #008080; ">21</span>&nbsp;<span style="color: #008000; "></span><span style="color: #0000FF; ">int</span>&nbsp;&nbsp;&nbsp;&nbsp;Thread::join()<br /><span style="color: #008080; ">22</span>&nbsp;{<br /><span style="color: #008080; ">23</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bExit_&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;<span style="color: #0000FF; ">true</span>;<br /><span style="color: #008080; ">24</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;notify();<br /><span style="color: #008080; ">25</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;apr_sleep(100000);<br /><span style="color: #008080; ">26</span>&nbsp;<br /><span style="color: #008080; ">27</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;apr_status_t&nbsp;rv&nbsp;=&nbsp;0;<br /><span style="color: #008080; ">28</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;apr_thread_join(&amp;rv,&nbsp;thr_);<br /><span style="color: #008080; ">29</span>&nbsp;}<br /><span style="color: #008080; ">30</span>&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">销毁线程</span><span style="color: #008000; "><br /></span><span style="color: #008080; ">31</span>&nbsp;<span style="color: #008000; "></span><span style="color: #0000FF; ">void</span>&nbsp;Thread::destroy()<br /><span style="color: #008080; ">32</span>&nbsp;{<br /><span style="color: #008080; ">33</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(!bExit_)<br /><span style="color: #008080; ">34</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;join();<br /><span style="color: #008080; ">35</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cond_.destroy();<br /><span style="color: #008080; ">36</span>&nbsp;}<br /><span style="color: #008080; ">37</span>&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">线程函数，将会调用子类实现的run()方法</span><span style="color: #008000; "><br /></span><span style="color: #008080; ">38</span>&nbsp;<span style="color: #008000; "></span><span style="color: #0000FF; ">void</span>*&nbsp;Thread::thread_proc(apr_thread_t*&nbsp;th,&nbsp;<span style="color: #0000FF; ">void</span>*&nbsp;data)<br /><span style="color: #008080; ">39</span>&nbsp;{<br /><span style="color: #008080; ">40</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Thread*&nbsp;pthis&nbsp;=&nbsp;static_cast&lt;Thread*&gt;(data);<br /><span style="color: #008080; ">41</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">while</span>&nbsp;(!pthis-&gt;bExit_)<br /><span style="color: #008080; ">42</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br /><span style="color: #008080; ">43</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">调用子类实现的run()方法</span><span style="color: #008000; "><br /></span><span style="color: #008080; ">44</span>&nbsp;<span style="color: #008000; "></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pthis-&gt;run();<br /><span style="color: #008080; ">45</span>&nbsp;<br /><span style="color: #008080; ">46</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">wait&nbsp;for&nbsp;signal</span><span style="color: #008000; "><br /></span><span style="color: #008080; ">47</span>&nbsp;<span style="color: #008000; "></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pthis-&gt;cond_.wait();<br /><span style="color: #008080; ">48</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br /><span style="color: #008080; ">49</span>&nbsp;<br /><span style="color: #008080; ">50</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf("thread&nbsp;exit,&nbsp;id:&nbsp;%d\n",&nbsp;pthis-&gt;get_thread_id());<br /><span style="color: #008080; ">51</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;apr_thread_exit(th,&nbsp;APR_SUCCESS);<br /><span style="color: #008080; ">52</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;NULL;<br /><span style="color: #008080; ">53</span>&nbsp;}</div><p style="margin: 0in; font-family: Calibri; font-size: 10.5pt;">&nbsp; &nbsp; 这里我们不要太过意研究线程在具体代码是如何创建的，比如在start()函数中，在windows下线程函数可以是 UINT thread_proc(LPVOID param); 而创建线程则是调用__beginthreadex()的windows API即可，具体可参照windows的线程创建和销毁逻辑。线程使用如下：</p>  <p style="margin:0in;font-family:SimSun;font-size:10.5pt"><strong>应用示例</strong></p>  <div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #008080; ">&nbsp;1</span>&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">继承Thread类并实现run()接口，有点类似Java或C#的用法</span><span style="color: #008000; "><br /></span><span style="color: #008080; ">&nbsp;2</span>&nbsp;<span style="color: #008000; "></span><span style="color: #0000FF; ">class</span>&nbsp;MyThread&nbsp;:&nbsp;<span style="color: #0000FF; ">public</span>&nbsp;Thread<br /><span style="color: #008080; ">&nbsp;3</span>&nbsp;{<br /><span style="color: #008080; ">&nbsp;4</span>&nbsp;<span style="color: #0000FF; ">public</span>:<br /><span style="color: #008080; ">&nbsp;5</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MyThread(){&nbsp;loop_&nbsp;=&nbsp;<span style="color: #0000FF; ">true</span>;&nbsp;}<br /><span style="color: #008080; ">&nbsp;6</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">virtual</span>&nbsp;MyThread(){}<br /><span style="color: #008080; ">&nbsp;7</span>&nbsp;<br /><span style="color: #008080; ">&nbsp;8</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">只关心如何实现业务逻辑，而看不到线程是如何创建的</span><span style="color: #008000; "><br /></span><span style="color: #008080; ">&nbsp;9</span>&nbsp;<span style="color: #008000; "></span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">virtual</span>&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;run()<br /><span style="color: #008080; ">10</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br /><span style="color: #008080; ">11</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">while</span>&nbsp;(loop)<br /><span style="color: #008080; ">12</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br /><span style="color: #008080; ">13</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">do&nbsp;some&nbsp;work</span><span style="color: #008000; "><br /></span><span style="color: #008080; ">14</span>&nbsp;<span style="color: #008000; "></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br /><span style="color: #008080; ">15</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf("MyThread&nbsp;exit.\n");<br /><span style="color: #008080; ">16</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br /><span style="color: #008080; ">17</span>&nbsp;<br /><span style="color: #008080; ">18</span>&nbsp;<span style="color: #0000FF; ">private</span>:<br /><span style="color: #008080; ">19</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">bool</span>&nbsp;loop_;<br /><span style="color: #008080; ">20</span>&nbsp;};<br /><span style="color: #008080; ">21</span>&nbsp;<br /><span style="color: #008080; ">22</span>&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;在程序中使用如下</span><span style="color: #008000; "><br /></span><span style="color: #008080; ">23</span>&nbsp;<span style="color: #008000; "></span>MyThread*&nbsp;pmt&nbsp;=&nbsp;<span style="color: #0000FF; ">new</span>&nbsp;MyThread();<br /><span style="color: #008080; ">24</span>&nbsp;pmt-&gt;start();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">调用start()方法后，即启动了一个线程了</span></div><p style="margin:0in;font-family:Calibri;font-size:10.5pt"><br />&nbsp; &nbsp; 这样，我们就完成了一个线程类的封装和使用了，代码不多，但很常用哈。最后说明一下线程类中使用一个Condition的类，其实也就是一个对事件的封装使用，完全可以用windows下的 SetEvent()/WaitForSingleObject()替代或Linux下的pthread_condition_t的pthrad_condition_signal()/pthread_condition_wait()替代，即等待事件和通知事件的处理。<br />&nbsp; &nbsp; 下一节我将会利用这个线程类实现一个简单的线程池，便于我们在程序中使用。</p><img src ="http://www.cppblog.com/Chosen/aggbug/203567.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Chosen/" target="_blank">Choice</a> 2013-10-07 18:12 <a href="http://www.cppblog.com/Chosen/archive/2013/10/07/203567.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>利用C/C++库函数读写文件的基本用法</title><link>http://www.cppblog.com/Chosen/archive/2013/07/21/202014.html</link><dc:creator>Choice</dc:creator><author>Choice</author><pubDate>Sun, 21 Jul 2013 11:50:00 GMT</pubDate><guid>http://www.cppblog.com/Chosen/archive/2013/07/21/202014.html</guid><wfw:comment>http://www.cppblog.com/Chosen/comments/202014.html</wfw:comment><comments>http://www.cppblog.com/Chosen/archive/2013/07/21/202014.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Chosen/comments/commentRss/202014.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Chosen/services/trackbacks/202014.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;本文分别简单讲述了如何利用C和C++库函数对文件的读写，涵盖了常用的文件操作函数。网上关于C/C++文件操作的介绍的博客很多，所以本文也大同小异，也主要是做一个备忘，不有每次都百度了。但本文重点在于几个库函数的运用，而不是从文件的属性或分类开始。<br />说明：由于本人水平有限或写博客时，打字疏忽再所难免。所以对于函数的使用有异议的请以msdn或相关标准文档为准，而本文主要是告诉你各个文件操作函数的功能和用法。<br />一、C文件操作：<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;C语言中，文件的操作都是通过一个FILE类型的文件指针进行，也就是说只有通过文件指针，才能调用相应的文件。FILE是一个由系统定义的结构体(定义在stdio.h中)，可以存放文件的相关信息。<br /><strong>文件的打开(fopen函数)</strong><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;文件的操作过程一般为：打开 =&gt; 读/写 =&gt; 关闭。<br />fopen函数的原型如下：<br />&nbsp;&nbsp;&nbsp;FILE* fopen(const char* filename, const char* mode); <br />函数调用就比较简单了：<br />&nbsp;&nbsp;&nbsp;FILE* fp;<br />&nbsp;&nbsp;&nbsp;fp = fopen("file1.txt", "r");<br />如果打开成功，返回file1.txt文件的指针，如果打开失败，返回一个NULL指针，所以调用fopen()后我们需要检查fp的值才进行下一步操作。fopen()的第一个参数为文件名，第二个参数为文件打开方式，含义如下表：<br /><font color="black">
<table border="1" width="559">
<tbody>
<tr>
<td width="202">
<p align="center">使用文件方式</p></td>
<td width="341">
<p align="center">含义</p></td></tr>
<tr>
<td width="202">"r"（只读）</td>
<td width="341">为输入打开一个<span style="color: red">文本</span>文件</td></tr>
<tr>
<td width="202">"w"（只写）</td>
<td width="341">为输出打开一个文本文件</td></tr>
<tr>
<td width="202">"a"（追加）</td>
<td width="341">为追加打开一个文本文件</td></tr>
<tr>
<td width="202">"rb"（只读）</td>
<td width="341">为输入打开一个<span style="color: red">二进制</span>文件</td></tr>
<tr>
<td width="202">"wb"（只写）</td>
<td width="341">为输出打开一个二进制文件</td></tr>
<tr>
<td width="202">"ab"（追加）</td>
<td width="341">为追加打开一个二进制文件</td></tr>
<tr>
<td width="202">"r+"（读写）</td>
<td width="341">为读／写打开一个文本文件</td></tr>
<tr>
<td width="202">"w+"（读写）</td>
<td width="341">为读／写创建一个文本文件</td></tr>
<tr>
<td width="202">"a+"（读写）</td>
<td width="341">为读／写打开一个文本文件</td></tr>
<tr>
<td width="202">"rb+"（读写）</td>
<td width="341">为读／写打开一个二进制文件</td></tr>
<tr>
<td width="202">"wb+"（读写）</td>
<td width="341">为读／写创建一个二进制文件</td></tr>
<tr>
<td width="202">"ab+"（读写）</td>
<td width="341">为读／写打开一个二进制文件</td></tr></tbody></table>
<p>说明：&nbsp;1. 使用"r"时，如果文件不存在，则出错。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2. 使用"w"时，如果没有文件，则创建一个新文件。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;3. 使用"a"时，如果希望向文件尾添加数据，则该文件必须存在，否则出错。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;4. "r+","w+","a+"都是可以输入和输出数据，但必须遵守上述3点<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;5. 操作二进制文件时，加上"b"字符，且二进制文件对换行符不会进行转换，而文本文件会将换行符转换为回车和换行两个字符。<br /><strong>文件的关闭（fclose函数）</strong><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;在使用完一个文件后，若不关闭则会造成系统资源泄漏。使用fclose()关闭文件即可，原型为 int fclose(FILE* fp)。使用：fclose(fp); flose()返回0时为顺利关闭文件，否则返回EOF(-1)。<br /><strong>文件的读写<br />&nbsp;&nbsp;&nbsp;</strong>1) fputc(), fgetc()分别为从文件流中写和读一个字符，原型分别如下：<br />&nbsp;&nbsp;&nbsp;写：int fputc(int c, FILE* fp);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;读：int fgetc(FILE* fp); 失败时均返回EOF<br />&nbsp;&nbsp;&nbsp;2) fputs(), fgets()分别为从文件流中写和读一个字符串，原型分别如下：<br />&nbsp;&nbsp;&nbsp;写：int fputs(const char* str, FILE* fp);&nbsp;&nbsp;例如： fputs("I love this game!", fp);<br />&nbsp;&nbsp;&nbsp;读：char* fgets(char* str, int n, FILE* fp); 从流中读取n-1个字符或读完一行，参数str用于接收读取的字符串。注意当读取一行时，不包括行尾的'\n'字符。<br />&nbsp;&nbsp;&nbsp;3) fseek() 一般用于二进制模式打开的文件中，功能是定位到流中指定的位置。原型如下：<br />&nbsp;&nbsp;&nbsp;int fseek(FILE* fp, lont offset, int whence); 参数offset是移动的字符数，whence是移动的基准，取值是：<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SEEK_SET 0 //文件开头&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SEEK_CUR 1 //当前读写的位置&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SEEK_END 2 //文件尾部&nbsp;<br />&nbsp;&nbsp;&nbsp;4) fprintf(),fscanf()是将数据按格式输出输入到文件流中，用法类似printf()和scanf()。原型分别如下：<br />&nbsp;&nbsp;&nbsp;int fprintf(FILE* fp, const char* format, ...); 它与printf()不同的就是将数据写到了文件流中，而不是控制台罢了。<br />&nbsp;&nbsp;&nbsp;int fscanf(FILE* fp, cosnt char* format, ...); 从文件流中按格式读取，与scanf()不同的就是数据是从文件流中读取而已。<br />&nbsp;&nbsp;&nbsp;例如： fprintf(fp, "count=%d", 5);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fscanf(fp, "%d", &amp;x);<br />&nbsp;&nbsp;&nbsp;5) feof()是检测是否已到文件尾，是返回真，否则返回0，原型是 int feof(FILE* fp);<br />&nbsp;&nbsp;&nbsp;6) rewind() 则是把当前的读写位置回到文件开始，相当于 fseek(fp, 0L, SEEK_SET); 原型： void rewind(FILE* fp);<br />&nbsp;&nbsp;&nbsp;7) remove() 删除文件，原型:&nbsp;int remove(const char* filename);&nbsp;&nbsp;参数为要删除的文件名，成功则返回0;<br />&nbsp;&nbsp;&nbsp;8) fread(), fwrite() 它们相当于可将一块的数据读出或写入，相当的方便。原型如下：<br />&nbsp;&nbsp;&nbsp;size_t fread(void* ptr, size_t size, size_t n, FILE* fp); 从流中读指定个数的字符，size是每块的字节娄，n则是读取的块数。<br />&nbsp;&nbsp;&nbsp;size_t fwrite(const void* ptr, size_t size, size_t n, FILE* fp); 类似的是向文件流中写入n块size字节数的数据。可以看到数据指针为void*型，即可以使用任何类型的指针来替换。例如：<br />现在一个结构体： struct student_t{char name[16]; int id; int age;}; 创建三个学生的数据并赋值：struct student_t stu[3];<br />这时，当我们找开文件后(一般是进制模式)，可以调用fwrite()将三个学生的数据都写入到文件中,两种方式：<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for(int i = 0; i &lt; 3; ++i)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fwrite(&amp;stu[i], sizeof(struct student_t), 1, fp);&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;或者：fwrite(stu, sizeof(struct student_t), 3, fp);<br />些时，我们调用fread()函数便可很轻松的将刚才写入的3个学生的数据读取出来：<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;struct student_t stus[3];<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for(int i = 0; i &lt; 3; ++i)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fread(&amp;stus[i], sizeof(struct student_t), 1, fp);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;或者：fread(stus, sizeof(struct student_t), 3, fp); 这样便可将三个学生的数据读入到stus变量中了(有木有很方便呐)<br />注意：如果你发现使用fread()读取之后，最后一个学生读取的数据不完全，可能是由于你没有使用二进制模式打开的原因。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;9) 最后是tmpfile()和tmpnam()，前者为生成一个临时文件，后者为生成一个唯一的文件名，具体使用在此不介绍了。<br />二、使用C++中的fstream文件流操作类进行文件的读写<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;使用fstream操作文件与使用C库函数类似，只不过fstream为面向对象方式，或多了上些C++的特性。首先，这里大概有三个流：<br />fstream为文件输入输出流，ifstream为输入文件流，ofstream为输出文件流，它们与ostream不同的就流的目的地为文件，而不是控制台。这里只介绍与上述的一些不同点：<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1. 打开文件，如可以是 ifstream input_file("file2.txt"); 这样将会以默认方式打开file2.txt文件并进行读取。也可使用open()方式打开一个文件，并指定打开方式，例如：<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ifstream input_file;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;input_file.open("file2.txt", ios::binary); <br />打开后，可以使用is_open()检测是否打开成功：<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(input_file.is_open()){}，然后可以使用流操作符向文件写数据了，例如：<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;input_file &lt;&lt; "this is a test line";<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;input_file &lt;&lt; "another info";<br />另外，这里的文件打开方式在ios空间下：<br />&nbsp;&nbsp;&nbsp;ios::app 添加到文件尾<br />&nbsp;&nbsp;&nbsp;ios::ate 把文件标志放在末尾而非起始。<br />&nbsp;&nbsp;&nbsp;ios::trunc 默认. 截断并覆写文件。<br />&nbsp;&nbsp;&nbsp;ios::nocreate 文件不存在也不创建。<br />&nbsp;&nbsp;&nbsp;ios::noreplace 文件存在则失败。<br />ofstream使用方式类似，读取一行数据可以使用getline(buf, count), 类型于fgets()。fstream类还提供一个很多其它方法，如fclose()为关闭文件，eof()用于检测状态是否已经到了文件末尾。<br />这里还有两个类似于上述的fread()和fwrite()函数，是read(), write()，功能和用法类似类似，例如：<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;output_file.write((const char*)stu, 3 *&nbsp;sizeof(struct student_t));<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;input_file.read((char*)stus, 3 * sizeof(struct student_t));<br />注意，这里也需要使用二进制模式打开，否则read的时候最后的上些数据读不完全。调用上面两个函数后可以使用bad()来检测文件流对象是否错误，例如，if(input_file.bad()){printf("error when read file\n"); return;}，最后input_file.close()即可。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;最后，C/C++文件的操作并不复杂，多使用几次便可熟练掌握，需要注意的就是文件的打开方式，和当用同一个文件指针进行又读又写时，注意文件指针位置的移动。<br /><br /><br /></p></font><img src ="http://www.cppblog.com/Chosen/aggbug/202014.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Chosen/" target="_blank">Choice</a> 2013-07-21 19:50 <a href="http://www.cppblog.com/Chosen/archive/2013/07/21/202014.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C++实现类似printf的不定参数函数</title><link>http://www.cppblog.com/Chosen/archive/2013/05/01/199878.html</link><dc:creator>Choice</dc:creator><author>Choice</author><pubDate>Wed, 01 May 2013 09:23:00 GMT</pubDate><guid>http://www.cppblog.com/Chosen/archive/2013/05/01/199878.html</guid><wfw:comment>http://www.cppblog.com/Chosen/comments/199878.html</wfw:comment><comments>http://www.cppblog.com/Chosen/archive/2013/05/01/199878.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/Chosen/comments/commentRss/199878.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Chosen/services/trackbacks/199878.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;其实，C++实现类似printf()函数的不定参数很简单，代码一写就明白了：
<div style="border-bottom: #cccccc 1px solid; border-left: #cccccc 1px solid; padding-bottom: 4px; background-color: #eeeeee; padding-left: 4px; width: 98%; padding-right: 5px; font-size: 13px; word-break: break-all; border-top: #cccccc 1px solid; border-right: #cccccc 1px solid; padding-top: 4px"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #008080">&nbsp;1</span>&nbsp;<span style="color: #0000ff">#define</span><span style="color: #000000">&nbsp;BUFFSIZE&nbsp;4096</span><span style="color: #000000"><br /></span><span style="color: #008080">&nbsp;2</span>&nbsp;<span style="color: #000000"><br /></span><span style="color: #008080">&nbsp;3</span>&nbsp;<span style="color: #000000"></span><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;Log2DebugView(</span><span style="color: #0000ff">const</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">char</span><span style="color: #000000">*</span><span style="color: #000000">&nbsp;format,&nbsp; ...)<br /></span><span style="color: #008080">&nbsp;4</span>&nbsp;<span style="color: #000000">{<br /></span><span style="color: #008080">&nbsp;5</span>&nbsp;<span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">char</span><span style="color: #000000">&nbsp;buf[BUFFSIZE];<br /></span><span style="color: #008080">&nbsp;6</span>&nbsp;<span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">char</span><span style="color: #000000">*</span><span style="color: #000000">&nbsp;p&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;buf;<br /></span><span style="color: #008080">&nbsp;7</span>&nbsp;<span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;va_list&nbsp;args;<br /></span><span style="color: #008080">&nbsp;8</span>&nbsp;<span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;va_start(args,&nbsp;format);<br /></span><span style="color: #008080">&nbsp;9</span>&nbsp;<span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;vsprintf(p,&nbsp;format,&nbsp;args);<br /></span><span style="color: #008080">10</span>&nbsp;<span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;va_end(args);<br /></span><span style="color: #008080">11</span>&nbsp;<span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000">//</span><span style="color: #008000">OutputDebugStringA(buf);</span><span style="color: #008000"><br /></span><span style="color: #008080">12</span>&nbsp;<span style="color: #008000"></span><span style="color: #000000">}</span></div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;其中最核心的就是第7到第10行，解析format字符串中的格式化参数，如 %c, %d 等。最后得到的'buf'，即是格式化后的字符串。比如调用了： <em>Log2DebugView("Test dbgview for id=%d, name=%s.", 5, "chosen");</em>&nbsp;然后buf的内容便是： "<em>Test dbgview for id=5, name=chosen.</em>"。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;至于最后的那句"OutptDebugString(buf);"，是一个系统调用函数，主要用于将格式化后信息输出到Visual Studio的'output'窗口中（Debug模式下），或者输出到一个叫"dbgView.exe"的程序窗口中（运行模式下）。这对于我们调试来说是一个非常有用的工具，而且程序运行完后，这些格式化后的信息，还会保留在output或debView的窗口中，供我们分析。注：dbgView.exe可以在网上搜索并免费下载使用。<br /><br /> <img src ="http://www.cppblog.com/Chosen/aggbug/199878.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Chosen/" target="_blank">Choice</a> 2013-05-01 17:23 <a href="http://www.cppblog.com/Chosen/archive/2013/05/01/199878.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>开源跨平台C++日志组件Log4cxx的入门级使用</title><link>http://www.cppblog.com/Chosen/archive/2013/04/29/199846.html</link><dc:creator>Choice</dc:creator><author>Choice</author><pubDate>Mon, 29 Apr 2013 10:39:00 GMT</pubDate><guid>http://www.cppblog.com/Chosen/archive/2013/04/29/199846.html</guid><wfw:comment>http://www.cppblog.com/Chosen/comments/199846.html</wfw:comment><comments>http://www.cppblog.com/Chosen/archive/2013/04/29/199846.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Chosen/comments/commentRss/199846.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Chosen/services/trackbacks/199846.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;由于上一文章已经讲述了如何在VS2010下编译log4cxx源码，将会生成两个文件：log4cxx.lib 和 log4cxx.dll。编译时导入该lib文件，运行时，需要确保该dll文件在程序运行目录或系统目录下即可。&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;下面来介绍一下该日志组件的使用，如果你是初次接触log4cxx，恭喜你，可以继续往下走，并可能得到一些帮助哦，那高手呢，就路过吧。（注：本人水平不限，疏忽之处再所难免，欢迎拍砖。）<br />&nbsp;&nbsp;&nbsp;1.&nbsp;&nbsp;&nbsp;概况： 要想使用log4cxx日志组件，除了需要上述两个文件外，还需要一个文本配置文件，一般命名为 logging.properties，loggging.config 等相关便于识别的字样。还就是在程序中导入相应的头文件，使用cofigure加载配置文件，然后得到一个LoggerPtr的指针，再进行日志的输入即可。日志的输入格式以及输入到哪儿，均是在配置文件中指定的。<br />&nbsp;&nbsp;&nbsp;2.&nbsp;&nbsp;&nbsp;配置文件简介：首先，配置文件格式大概如下所示，你可以按照要求格式自己写，也可以从其它地方copy一个过来。这里也做一些简单的介绍。一个配置文件中可能包含多个以下文本段，一般以后这么些行文本表示一个logger，即在你的项目中，可能会把不同的项目功能分支，输出到不同的日志里，在些指定多个logger及输入文件即可。下面来简单介绍一下其中一些行的含意：<br />
<div style="border-bottom: #cccccc 1px solid; border-left: #cccccc 1px solid; padding-bottom: 4px; background-color: #eeeeee; padding-left: 4px; width: 98%; padding-right: 5px; font-size: 13px; word-break: break-all; border-top: #cccccc 1px solid; border-right: #cccccc 1px solid; padding-top: 4px"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #008080">1</span><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" /><span style="color: #000000">log4j.logger.TradeServer</span><span style="color: #000000">=</span><span style="color: #000000">DEBUG,&nbsp;B<br /></span><span style="color: #008080">2</span><span style="color: #000000"><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" />#log4j.appender.B</span><span style="color: #000000">=</span><span style="color: #000000">org.apache.log4j.RollingFileAppender<br /></span><span style="color: #008080">3</span><span style="color: #000000"><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" />log4j.appender.B</span><span style="color: #000000">=</span><span style="color: #000000">org.apache.log4j.DailyRollingFileAppender<br /></span><span style="color: #008080">4</span><span style="color: #000000"><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" />log4j.appender.B.File</span><span style="color: #000000">=</span><span style="color: #000000">log</span><span style="color: #000000">/</span><span style="color: #000000">myclient.log<br /></span><span style="color: #008080">5</span><span style="color: #000000"><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" />#log4j.appender.B.MaxFileSize</span><span style="color: #000000">=</span><span style="color: #000000">5000KB<br /></span><span style="color: #008080">6</span><span style="color: #000000"><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" />#log4j.appender.B.MaxBackupIndex</span><span style="color: #000000">=</span><span style="color: #000000">10</span><span style="color: #000000"><br /></span><span style="color: #008080">7</span><span style="color: #000000"><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" />log4j.appender.B.DatePattern</span><span style="color: #000000">=</span><span style="color: #000000">'</span><span style="color: #000000">.</span><span style="color: #000000">'</span><span style="color: #000000">yyyy</span><span style="color: #000000">-</span><span style="color: #000000">MM</span><span style="color: #000000">-</span><span style="color: #000000">dd<br /></span><span style="color: #008080">8</span><span style="color: #000000"><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" />log4j.appender.B.layout</span><span style="color: #000000">=</span><span style="color: #000000">org.apache.log4j.PatternLayout<br /></span><span style="color: #008080">9&nbsp; </span><span style="color: #000000">log4j.appender.B.layout.ConversionPattern</span><span style="color: #000000">=%</span><span style="color: #000000">d</span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_402_410_Closed_Text"></span><span id="Codehighlighter1_402_410_Open_Text"><span style="color: #000000">{ISO8601}</span></span><span style="color: #000000">&nbsp;</span><span style="color: #000000">%</span><span style="color: #000000">5p&nbsp;</span><span style="color: #000000">%-</span><span style="color: #000000">11c</span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_421_423_Closed_Text"></span><span id="Codehighlighter1_421_423_Open_Text"><span style="color: #000000">{</span><span style="color: #000000">1</span><span style="color: #000000">}</span></span><span style="color: #000000">&nbsp;</span><span style="color: #000000">-</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">%</span><span style="color: #000000">m</span><span style="color: #000000">%</span><span style="color: #000000">n</span></div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;行1：指定了logger的名字为"<strong>TradeServer</strong>",&nbsp;即在程序代码中可以这样得到此logger：<br /><em>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;log4cxx::LoggerPtr&nbsp;logger = log4cxx::Logger::getLogger("TradeServer");&nbsp;&nbsp;&nbsp;</em>然后还指定了该logger为DEBUG级别，<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;以及一个appender："B"， 可以观察到接下来2-9行，均有".appender.B"字样。至于关于更详细配置信息的讲解，百度一下。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;行4：日志将会输出到程序要目录下的 log 目录下的 <strong>myclient.log</strong> 文件中，当然可以改为你喜欢的日志文件名。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;行7：为日志输出的时间格式<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;行8：使用何种日志方式，log4cxx默认有几种layout，这里就不介绍了<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;行9：为日志信息输出的格式<br />&nbsp;&nbsp;&nbsp;2. 配置文件写好后，假如文件名为：<strong>logging.config</strong>&nbsp;，文件名将在程序代码中加载log4cxx的配置文件时使用，比如：<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;log4cxx::PropertyConfigurator::configure("conf/<strong>logging.config</strong>");<br />&nbsp;&nbsp;&nbsp;3. 示例代码：
<div style="border-bottom: #cccccc 1px solid; border-left: #cccccc 1px solid; padding-bottom: 4px; background-color: #eeeeee; padding-left: 4px; width: 98%; padding-right: 5px; font-size: 13px; word-break: break-all; border-top: #cccccc 1px solid; border-right: #cccccc 1px solid; padding-top: 4px"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #008080">1</span><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif"  alt="" /><span style="color: #008000">//</span><span style="color: #008000">&nbsp;load&nbsp;the&nbsp;configure&nbsp;file</span><span style="color: #008000"><br /></span><span style="color: #008080">2</span><span style="color: #008000"><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif"  alt="" /></span><span style="color: #000000">log4cxx::PropertyConfigurator::configure(_T(</span><span style="color: #000000">"</span><span style="color: #000000">conf/logging.properties</span><span style="color: #000000">"</span><span style="color: #000000">));<br /></span><span style="color: #008080">3</span><span style="color: #000000"><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif"  alt="" /></span><span style="color: #008000">//</span><span style="color: #008000">&nbsp;get&nbsp;the&nbsp;"TradeServer"&nbsp;logger</span><span style="color: #008000"><br /></span><span style="color: #008080">4</span><span style="color: #008000"><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif"  alt="" /></span><span style="color: #000000">log4cxx::LoggerPtr&nbsp;&nbsp;&nbsp;&nbsp;logger&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;log4cxx::Logger::getLogger(</span><span style="color: #000000">"</span><span style="color: #000000">TradeServer</span><span style="color: #000000">"</span><span style="color: #000000">);<br /></span><span style="color: #008080">5</span><span style="color: #000000"><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif"  alt="" /></span><span style="color: #008000">//</span><span style="color: #008000">&nbsp;log&nbsp;info<br /></span><span style="color: #008080">6</span><span style="color: #008000"><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif"  alt="" /></span><span style="color: #008000">//</span><span style="color: #008000">LOG4CXX_INFO(log4cxx::Logger::getLogger("TradeServer"),&nbsp;"Trade&nbsp;Server&nbsp;running...");</span><span style="color: #008000"><br /></span><span style="color: #008080">7</span><span style="color: #008000"><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif"  alt="" /></span><span style="color: #000000">LOG4CXX_INFO(logger,&nbsp;</span><span style="color: #000000">"</span><span style="color: #000000">Trade&nbsp;Server&nbsp;running...</span><span style="color: #000000">"</span><span style="color: #000000">);<br /></span><span style="color: #008080">8</span><span style="color: #000000"><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif"  alt="" /></span><span style="color: #008000">//</span><span style="color: #008000">&nbsp;log&nbsp;error</span><span style="color: #008000"><br /></span><span style="color: #008080">9</span><span style="color: #008000"><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif"  alt="" /></span><span style="color: #000000">LOG4CXX_ERROR(logger,&nbsp;</span><span style="color: #000000">"</span><span style="color: #000000">run:&nbsp;error=</span><span style="color: #000000">"</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">&lt;&lt;</span><span style="color: #000000">&nbsp;rv&nbsp;</span><span style="color: #000000">&lt;&lt;</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">"</span><span style="color: #000000">,&nbsp;errbuf=</span><span style="color: #000000">"</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">&lt;&lt;</span><span style="color: #000000">&nbsp;errbuf);</span></div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;上述第2行在程序运行时加载配置即可，第4行可以作为全局logger，即可以其它地方使用了。在宏的logger后面，可以使用流操作符写信息，很方便的哦(其实个人感觉有时候不太方便！)，另外还有一些其它级别的logger，如LOG4CXX_AAA等，具体可以百度的。<br />&nbsp;&nbsp;&nbsp;4. Log4cxx的简单使用就介绍到这儿啦。log4cxx功能很强大，也还有很多东西我在这儿也没介绍到，还需要多研究学习。但简单的使用是不是并没有想象中的那么难啊~  <img src ="http://www.cppblog.com/Chosen/aggbug/199846.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Chosen/" target="_blank">Choice</a> 2013-04-29 18:39 <a href="http://www.cppblog.com/Chosen/archive/2013/04/29/199846.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>VS2010编译log4cxx-0.10.0</title><link>http://www.cppblog.com/Chosen/archive/2013/04/29/199842.html</link><dc:creator>Choice</dc:creator><author>Choice</author><pubDate>Mon, 29 Apr 2013 09:42:00 GMT</pubDate><guid>http://www.cppblog.com/Chosen/archive/2013/04/29/199842.html</guid><wfw:comment>http://www.cppblog.com/Chosen/comments/199842.html</wfw:comment><comments>http://www.cppblog.com/Chosen/archive/2013/04/29/199842.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Chosen/comments/commentRss/199842.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Chosen/services/trackbacks/199842.html</trackback:ping><description><![CDATA[&nbsp; 
<p style="margin: 0in; font-family: Calibri; font-size: 10.5pt">初次在cppblog写博客，希望未来越写越好，与大家分享探讨技术人生(说起来都没底气=_=)。<br />Log4cxx是业界跨平台日志组件中用得比较广泛的，具体的介绍说明这里就不多了，百度一下，你就知道。本文章主要讲述了源码如何在VS2010中编译成功，至于简单的使用将在下一篇博文是讲述。<br /></p>
<p style="margin: 0in; font-size: 10.5pt"><span style="font-family: Calibri">最近，项目leader说要用到apache-log4cxx- 0.10.0</span><span style="font-family: SimSun">，让我先熟悉一下。便从</span><span style="font-family: Calibri"> </span><a href="http://www.apache.org/"><span style="font-family: Calibri">www.apache.org</span></a><span style="font-family: Calibri"> </span><span style="font-family: SimSun">分别下载了</span><span style="font-family: Calibri"> apache-log4cxx-0.10.0.zip , apr-1.4.6-win32-src.zip , apr-util-1.5.1-win32-src.zip </span><span style="font-family: SimSun">三个开源源码包。看来要使用的话还必须先编译成库文件才是。</span><span style="font-family: Calibri">apr </span><span style="font-family: SimSun">和</span><span style="font-family: Calibri"> apr-util&nbsp; </span><span style="font-family: SimSun">编译倒是没什么问题，但</span><span style="font-family: Calibri"> log4cxx </span><span style="font-family: SimSun">就遇到一些问题了。从网上找了些答案，已记不清原网络链接了，所以也在这里写一篇文章以备日后查看。</span></p>
<p style="margin: 0in; font-family: Calibri; font-size: 10.5pt">切入正题，步骤大概如下：</p>
<p style="margin: 0in; font-family: Calibri; font-size: 10.5pt">1. 到Apache站点上下载上述三个源码包</p>
<p style="margin: 0in; font-size: 10.5pt"><span style="font-family: Calibri">2. 将源码包解压至同一目录下，并更改目录名： apr-1.4.6 改为 </span><span style="font-family: Calibri; font-weight: bold">apr</span><span style="font-family: SimSun">，将</span><span style="font-family: Calibri"> apr-util-1.5.1 </span><span style="font-family: SimSun">改为</span><span style="font-family: Calibri; font-weight: bold">apr-util</span></p>
<p style="margin: 0in; font-size: 10.5pt"><span style="font-family: Calibri">3. 在开始菜单的VS2010目录下，启动&#8220;</span><span style="font-family: Calibri; font-weight: bold">Visual Studio 命令提示(2010)</span><span style="font-family: Calibri">&#8221;</span><span style="font-family: SimSun">，并切换到</span><span style="font-family: Calibri"> apache-log4cxx-0.10.0 </span><span style="font-family: SimSun">目录下，运行</span><span style="font-family: Calibri"> </span><span style="font-family: Calibri; font-weight: bold">configure.bat </span></p>
<p style="margin: 0in; font-size: 10.5pt"><span style="font-family: Calibri">4. 执行完上述命令后，再运行 </span><span style="font-family: Calibri; font-weight: bold">configure-aprutil.bat</span><span style="font-family: SimSun">，这时可能会提示</span><span style="font-family: Calibri"> &#8216;sed&#8217; </span><span style="font-family: SimSun">不是内部或外部命令</span><span style="font-family: Calibri">xxx</span><span style="font-family: SimSun">，这时我是装了一个</span><span style="font-family: Calibri"> Cygwin</span><span style="font-family: SimSun">，关于</span><span style="font-family: Calibri">Cygwin</span><span style="font-family: SimSun">的安装可能参考如下</span><span style="font-family: Calibri"> </span><a href="http://www.cygwin.cn/site/install/"><span style="font-family: Calibri">http://www.cygwin.cn/site/install/</span></a><span style="font-family: Calibri"> </span><span style="font-family: SimSun">然后在我的电脑属性里设置环境变量，在</span><span style="font-family: Calibri">path</span><span style="font-family: SimSun">变量中加入如：</span><span style="font-family: Calibri"> G:\cygwin\bin</span><span style="font-family: SimSun">。</span><span style="font-family: Calibri"> </span><span style="font-family: SimSun">至于</span><span style="font-family: Calibri">Cygwin</span><span style="font-family: SimSun">在安装过程中会有一个步骤让你选择安装哪些包，这时可以输入</span><span style="font-family: Calibri"> sed </span><span style="font-family: SimSun">关键字过滤选项即可，然后沟选相应的包安装即可。</span></p>
<p style="margin: 0in; font-size: 10.5pt"><span style="font-family: Calibri">5. 再运行 </span><span style="font-family: Calibri; font-weight: bold">configure-aprutil.bat</span><span style="font-family: SimSun">，现在应该会出现</span><span style="font-family: Calibri"> cygwin warning</span><span style="font-family: SimSun">等信息</span></p>
<p style="margin: 0in; font-family: Calibri; font-size: 10.5pt">6. 启动VS2010并打开 apache-log4cxx-0.10.0\projects\ 下的 log4cxx.dsw 工程，然后选择 &#8220;是&#8221;，转换并打开此项目</p>
<p style="margin: 0in; font-family: Calibri; font-size: 10.5pt">7. 将 log4cxx设置为启动项，然后开始编译</p>
<p style="margin: 0in; font-family: Calibri; font-size: 10.5pt">8. 此时可能会出现以下一些错误，一一处理即可：</p>
<p style="margin: 0in; font-size: 10.5pt"><span style="font-family: Calibri">&nbsp;&nbsp;&nbsp; 1</span><span style="font-family: SimSun">）</span><span style="font-family: calibri">xxx\apache-log4cxx-0.10.0\src\main\include\log4cxx/spi/loggingevent.h(155):error C2252: </span><span style="font-family: simsun; font-weight: bold">只能在命名空间范围内显式实例化模板</span><span style="font-family: calibri; font-weight: bold">' </span><span style="font-family: simsun; font-weight: bold">错误</span><span style="font-family: calibri; font-weight: bold">.</span><span style="font-family: Calibri"> </span></p>
<p style="margin: 0in 0in 0in 0.375in; font-family: Calibri; font-size: 10.5pt">a)双击 "输出" 窗口中的错误行, 此时会在 "代码窗口" 中出现错误的位置.</p>
<p style="margin: 0in 0in 0in 0.375in; font-family: Calibri; font-size: 10.5pt">b)选择 LOG4CXX_LIST_DEF, 按键盘 F12, 此时会跳转到该宏的定义</p>
<p style="margin: 0in 0in 0in 0.375in; font-family: Calibri; font-size: 10.5pt">c)将</p>
<p style="margin: 0in 0in 0in 0.375in; font-family: Calibri; color: red; font-size: 10.5pt">#define LOG4CXX_LIST_DEF(N, T) \</p>
<p style="margin: 0in 0in 0in 0.375in; font-family: Calibri; color: red; font-size: 10.5pt">template class LOG4CXX_EXPORT std::allocator&lt;T&gt;; \</p>
<p style="margin: 0in 0in 0in 0.375in; font-family: Calibri; color: red; font-size: 10.5pt">template class LOG4CXX_EXPORT std::vector&lt;T&gt;; \</p>
<p style="margin: 0in 0in 0in 0.375in; font-family: Calibri; color: red; font-size: 10.5pt">typedef std::vector&lt;T&gt; N</p>
<p style="margin: 0in 0in 0in 0.375in; font-family: Calibri; font-size: 10.5pt">注释掉，替换为:</p>
<p style="margin: 0in 0in 0in 0.375in; font-family: Calibri; color: green; font-size: 10.5pt">#define LOG4CXX_LIST_DEF(N, T) \</p>
<p style="margin: 0in 0in 0in 0.375in; font-family: Calibri; color: green; font-size: 10.5pt">typedef std::vector&lt;T&gt; N</p>
<p style="margin: 0in; font-size: 10.5pt"><span style="font-family: Calibri">&nbsp;&nbsp;&nbsp; 2</span><span style="font-family: SimSun">）</span><span style="font-family: calibri">network_io\unix\multicast.c(137): error C2079:&#8220;mip&#8221;</span><span style="font-family: simsun; font-weight: bold">使用未定义的</span><span style="font-family: calibri; font-weight: bold"> struct&#8220;group_source_req"' </span><span style="font-family: simsun; font-weight: bold">等错误</span><span style="font-family: calibri">.</span><span style="font-family: Calibri"> </span></p>
<p style="margin: 0in; font-size: 10.5pt"><span style="font-family: Calibri">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="font-family: SimSun">双击第一行出错输出</span><span style="font-family: Calibri">, </span><span style="font-family: SimSun">将</span><span style="font-family: Calibri"> 136 </span><span style="font-family: SimSun">和</span><span style="font-family: Calibri">148 </span><span style="font-family: SimSun">行的</span></p>
<p style="margin: 0in; font-size: 10.5pt"><span style="font-family: Calibri">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #if MCAST_JOIN_SOURCE_GROUP&nbsp; </span><span style="font-family: SimSun">注释</span><span style="font-family: Calibri">, </span><span style="font-family: SimSun">替换为</span></p>
<p style="margin: 0in; font-family: Calibri; font-size: 10.5pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #if defined (group_source_req)</p>
<p style="margin: 0in; font-size: 10.5pt"><span style="font-family: Calibri">&nbsp;&nbsp;&nbsp; 3</span><span style="font-family: SimSun">）</span><span style="font-family: Calibri">xxx </span><span style="font-family: calibri">\src\main\cpp\stringhelper.cpp(64): error C2039: </span><span style="font-family: calibri; font-weight: bold">&#8220;insert_iterator&#8221;: </span><span style="font-family: simsun; font-weight: bold">不是&#8220;</span><span style="font-family: calibri; font-weight: bold">std</span><span style="font-family: simsun; font-weight: bold">&#8221;的成员</span><span style="font-family: calibri; font-weight: bold">' </span><span style="font-family: simsun; font-weight: bold">等错误</span><span style="font-family: calibri; font-weight: bold">.</span></p>
<p style="margin: 0in; font-size: 10.5pt"><span style="font-family: Calibri">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="font-family: SimSun">在该</span><span style="font-family: Calibri">.cpp </span><span style="font-family: SimSun">中</span><span style="font-family: Calibri">(stringhelper.cpp) </span><span style="font-family: SimSun">加入头文件</span><span style="font-family: Calibri"> #include &lt;iterator&gt;</span></p>
<p style="margin: 0in; font-size: 10.5pt"><span style="font-family: Calibri">&nbsp;&nbsp;&nbsp; 4</span><span style="font-family: SimSun">）</span><span style="font-family: SimSun; font-weight: bold">无法解析的外部符号</span><span style="font-family: Calibri; font-weight: bold"> xxx' </span><span style="font-family: SimSun; font-weight: bold">等错误</span></p>
<p style="margin: 0in; font-size: 10.5pt"><span style="font-family: Calibri">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="font-family: SimSun">则右键</span><span style="font-family: Calibri">log4cxx</span><span style="font-family: SimSun">项目属性，通用属性</span><span style="font-family: Calibri"> | </span><span style="font-family: SimSun">框架和引用，将</span><span style="font-family: Calibri">apr, aprutil, xml </span><span style="font-family: SimSun">添加至</span><span style="font-family: Calibri"> log4cxx </span><span style="font-family: SimSun">的引用中</span></p>
<p style="margin: 0in; font-family: Calibri; font-size: 10.5pt">9. 选择重新生成解决方案即可，编译将得到 log4cxx.lib 和 log4cxx.dll 两个文件</p>
<p style="margin: 0in; font-family: Calibri; font-size: 10.5pt">编译成功后，就可以将该lib和dll文件在你的项目中应用了哦~<br />简单使用介绍将在下一节介绍。</p> <img src ="http://www.cppblog.com/Chosen/aggbug/199842.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Chosen/" target="_blank">Choice</a> 2013-04-29 17:42 <a href="http://www.cppblog.com/Chosen/archive/2013/04/29/199842.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>