??xml version="1.0" encoding="utf-8" standalone="yes"?>精品熟女少妇aⅴ免费久久,亚洲精品无码久久久久AV麻豆,久久偷看各类wc女厕嘘嘘http://www.shnenglu.com/true/category/3902.htmlzh-cnMon, 09 Jul 2012 22:26:49 GMTMon, 09 Jul 2012 22:26:49 GMT60linux常用命o搜集http://www.shnenglu.com/true/archive/2012/07/09/182263.htmltruetrueSun, 08 Jul 2012 18:07:00 GMThttp://www.shnenglu.com/true/archive/2012/07/09/182263.htmlhttp://www.shnenglu.com/true/comments/182263.htmlhttp://www.shnenglu.com/true/archive/2012/07/09/182263.html#Feedback0http://www.shnenglu.com/true/comments/commentRss/182263.htmlhttp://www.shnenglu.com/true/services/trackbacks/182263.html1.awk使用
http://sunting.blog.51cto.com/1244382/281472
http://brantc.blog.51cto.com/410705/199901
http://www.cnblogs.com/zhanglanyun/archive/2011/10/02/2198015.html

2.sort
http://www.cnblogs.com/kumuspring/archive/2011/07/17/2149237.html


true 2012-07-09 02:07 发表评论
]]>
lZThread提供一个patchhttp://www.shnenglu.com/true/archive/2011/05/29/147632.htmltruetrueSun, 29 May 2011 09:44:00 GMThttp://www.shnenglu.com/true/archive/2011/05/29/147632.htmlhttp://www.shnenglu.com/true/comments/147632.htmlhttp://www.shnenglu.com/true/archive/2011/05/29/147632.html#Feedback0http://www.shnenglu.com/true/comments/commentRss/147632.htmlhttp://www.shnenglu.com/true/services/trackbacks/147632.htmlhttp://zthread.sourceforge.net/  
 q个库设计的很小巧,优雅Q符合我个h的审观Qlinux下通过~译时会出现错误Q主要是׃gcc的老语法所_׃库的作?005q停止了更新Q所以这一块一直没改,q里提供一个patchQ其实很单,是替换了下几个语句Q内容ؓQ?span class="Apple-style-span" style="font-size: 13px; ">     
#(0) put this file under top ZThread directory,such as ZThread-2.3.2/,and
#(
1) cd ZThread-2.3.2
#(
2) ./zthread-patch.sh  (chmod +x zthread-patch.sh if necessary)
#(
3) ./configure
#(
4) make

sed 
-'/if(!isDisabled())/s/^.*/    if(!this->isDisabled())/' ./include/zthread/Guard.h
sed 
-'/waiterArrived(self)/s/^.*/      this->waiterArrived(self);/' ./src/MutexImpl.h
sed 
-'/waiterDeparted(self)/s/^.*/      this->waiterDeparted(self);/' ./src/MutexImpl.h
sed 
-'/ownerAcquired(self)/s/^.*/      this->ownerAcquired(self);/' ./src/MutexImpl.h
sed 
-'/ownerReleased(impl)/s/^.*/      this->ownerReleased(impl);/' ./src/MutexImpl.h


true 2011-05-29 17:44 发表评论
]]>
tcpdump的常用方?/title><link>http://www.shnenglu.com/true/archive/2011/05/25/147104.html</link><dc:creator>true</dc:creator><author>true</author><pubDate>Wed, 25 May 2011 10:53:00 GMT</pubDate><guid>http://www.shnenglu.com/true/archive/2011/05/25/147104.html</guid><wfw:comment>http://www.shnenglu.com/true/comments/147104.html</wfw:comment><comments>http://www.shnenglu.com/true/archive/2011/05/25/147104.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/true/comments/commentRss/147104.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/true/services/trackbacks/147104.html</trackback:ping><description><![CDATA[<p>1.sudo /usr/sbin/tcpdump -i eth1 -n port 7999</p> <p>2.sudo /usr/sbin/tcpdump -i any -X -n -s0 port 7999</p> <p>3.sudo /usr/sbin/tcpdump -i any -X -n -s0 dst port  7999 and ip[39]==0 and ip[40]==2<br />最后的 ip[39]==0 and ip[40]==0是过滤条Ӟ含义为,从ip头开始算LW?9个字节ؓ十进?Q第40个字节ؓ十进?</p><img src ="http://www.shnenglu.com/true/aggbug/147104.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/true/" target="_blank">true</a> 2011-05-25 18:53 <a href="http://www.shnenglu.com/true/archive/2011/05/25/147104.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C++实现的MD5法http://www.shnenglu.com/true/archive/2010/09/04/125888.htmltruetrueSat, 04 Sep 2010 12:03:00 GMThttp://www.shnenglu.com/true/archive/2010/09/04/125888.htmlhttp://www.shnenglu.com/true/comments/125888.htmlhttp://www.shnenglu.com/true/archive/2010/09/04/125888.html#Feedback1http://www.shnenglu.com/true/comments/commentRss/125888.htmlhttp://www.shnenglu.com/true/services/trackbacks/125888.htmlhttp://www.shnenglu.com/Files/true/md5lib.rar
         使用说明Q?br>         Q?Q源代码主要提供了MD5c,在类之外提供了两个函敎ͼ
                              std::string getMD5(std::ifstream& stream);//q个是文件接口,计算文g内容的MD5
                              std::string getMD5(const char* str,unsigned int str_len);//q个׃用说?br>想研I代码的话,参考MD5cȝ实现Q如果只是用的话Q只需会用上面的接口即?br>         Q?Qstd::string getMD5(const char* str,unsigned int str_len)的用:
                                    string sName = "MD5";
                                    string sMD5  = getMD5(sName.c_str(),sName.length());
此时sMD5的gؓQ?f138a09169b250e9dcb378140907378
         Q?Qstd::string getMD5(std::ifstream& stream)的用:创徏md5.txtQ内容ؓQMD5
                                    ifstream file("md5.txt");
                                    string sMD5File = getMD5(file);
sMD5File 的也是:7f138a09169b250e9dcb378140907378
         Q?Qlinux下提供md5sum,上面的md5.txt传到linux下,然后Qmd5sum md5.txtQ结果和上面一栗注意,一定要认md5.txt内容?个字节,如果直接d上linuxQ用vi创徏md5.txtQ然后输?#8220;MD5”Q最后保存,q种方式linux下会q加一个空行,DMD5g一致?br>         Q?Q安全意识要树立Q这个网?a >http://www.cmd5.com/以网Ş式提供md5解密Q将上面?f138a09169b250e9dcb378140907378的输入,几秒旉Q得到MD5

true 2010-09-04 20:03 发表评论
]]>
OCCI在linux上的~译警告http://www.shnenglu.com/true/archive/2009/03/19/77181.htmltruetrueThu, 19 Mar 2009 06:06:00 GMThttp://www.shnenglu.com/true/archive/2009/03/19/77181.htmlhttp://www.shnenglu.com/true/comments/77181.htmlhttp://www.shnenglu.com/true/archive/2009/03/19/77181.html#Feedback0http://www.shnenglu.com/true/comments/commentRss/77181.htmlhttp://www.shnenglu.com/true/services/trackbacks/77181.html   makefile的部分输出:
gcc -o ./testocci test.o -lpthread -lstdc++ -ldl -L/export/home/oracle/instantclient_10_2 -locci -lclntsh
/usr/bin/ld: warning: libstdc++.so.5, needed by /export/home/oracle/instantclient_10_2/libocci.so, may conflict with libstdc++.so.6

  makefile改ؓQ?br>gcc -o ./testocci test.o -lpthread -lstdc++ -ldl -L/export/home/oracle/instantclient_10_2 -locci -lclntsh  /usr/lib/libstdc++.so.5
警告消失



true 2009-03-19 14:06 发表评论
]]>
修改内核的部分参?/title><link>http://www.shnenglu.com/true/archive/2009/02/04/72951.html</link><dc:creator>true</dc:creator><author>true</author><pubDate>Wed, 04 Feb 2009 01:30:00 GMT</pubDate><guid>http://www.shnenglu.com/true/archive/2009/02/04/72951.html</guid><wfw:comment>http://www.shnenglu.com/true/comments/72951.html</wfw:comment><comments>http://www.shnenglu.com/true/archive/2009/02/04/72951.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/true/comments/commentRss/72951.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/true/services/trackbacks/72951.html</trackback:ping><description><![CDATA[         ?proc/sys/kernel目录下,可以修改消息队列的参数msgmax,msgmnb,msgmni,q有如终端显C的hostname{?在os重启动时Q所有的参数׃恢复到默认|如果惛_pȝ重启后,修改依然有效Q则可以修改/etc/sysctl.conf文gQ以修改hostnameZQ?br>         echo "kernel.hostname=VMware"  >>/etc/sysctl.conf<br>         /sbin/sysctl -p <br>         <img src ="http://www.shnenglu.com/true/aggbug/72951.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/true/" target="_blank">true</a> 2009-02-04 09:30 <a href="http://www.shnenglu.com/true/archive/2009/02/04/72951.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>基础库的错误信息应该如何处理http://www.shnenglu.com/true/archive/2009/02/02/72811.htmltruetrueMon, 02 Feb 2009 08:42:00 GMThttp://www.shnenglu.com/true/archive/2009/02/02/72811.htmlhttp://www.shnenglu.com/true/comments/72811.htmlhttp://www.shnenglu.com/true/archive/2009/02/02/72811.html#Feedback0http://www.shnenglu.com/true/comments/commentRss/72811.htmlhttp://www.shnenglu.com/true/services/trackbacks/72811.html阅读全文

true 2009-02-02 16:42 发表评论
]]>
对基本类型的再包装,方便了移?/title><link>http://www.shnenglu.com/true/archive/2009/02/02/72782.html</link><dc:creator>true</dc:creator><author>true</author><pubDate>Mon, 02 Feb 2009 02:51:00 GMT</pubDate><guid>http://www.shnenglu.com/true/archive/2009/02/02/72782.html</guid><wfw:comment>http://www.shnenglu.com/true/comments/72782.html</wfw:comment><comments>http://www.shnenglu.com/true/archive/2009/02/02/72782.html#Feedback</comments><slash:comments>12</slash:comments><wfw:commentRss>http://www.shnenglu.com/true/comments/commentRss/72782.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/true/services/trackbacks/72782.html</trackback:ping><description><![CDATA[     摘要: 对基本类型的再包?nbsp; <a href='http://www.shnenglu.com/true/archive/2009/02/02/72782.html'>阅读全文</a><img src ="http://www.shnenglu.com/true/aggbug/72782.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/true/" target="_blank">true</a> 2009-02-02 10:51 <a href="http://www.shnenglu.com/true/archive/2009/02/02/72782.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>自己造的一个线E类http://www.shnenglu.com/true/archive/2009/01/19/72306.htmltruetrueMon, 19 Jan 2009 04:54:00 GMThttp://www.shnenglu.com/true/archive/2009/01/19/72306.htmlhttp://www.shnenglu.com/true/comments/72306.htmlhttp://www.shnenglu.com/true/archive/2009/01/19/72306.html#Feedback12http://www.shnenglu.com/true/comments/commentRss/72306.htmlhttp://www.shnenglu.com/true/services/trackbacks/72306.html阅读全文

true 2009-01-19 12:54 发表评论
]]>
linux下信号处理函数实现的一点理?/title><link>http://www.shnenglu.com/true/archive/2009/01/15/72072.html</link><dc:creator>true</dc:creator><author>true</author><pubDate>Thu, 15 Jan 2009 03:39:00 GMT</pubDate><guid>http://www.shnenglu.com/true/archive/2009/01/15/72072.html</guid><wfw:comment>http://www.shnenglu.com/true/comments/72072.html</wfw:comment><comments>http://www.shnenglu.com/true/archive/2009/01/15/72072.html#Feedback</comments><slash:comments>6</slash:comments><wfw:commentRss>http://www.shnenglu.com/true/comments/commentRss/72072.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/true/services/trackbacks/72072.html</trackback:ping><description><![CDATA[<p>代码操作步骤如下Q?br><br>[tqg@localhost test]$ vi test.cpp </p> <p><br>#include <pthread.h><br>#include <signal.h><br>#include <stdio.h><br>#include <unistd.h></p> <p>void signal_handler(int sig)<br>{<br>        printf("catch signal: %d,thread id = %u\n",sig,pthread_self());<br>        pthread_exit(0);<br>}</p> <p>void* thread_handler(void*arg)<br>{<br>        signal(SIGQUIT,signal_handler);</p> <p>        printf("thread arg = %s\n",(char*)arg);</p> <p>        sleep(10);<br>        printf("in thread\n");</p> <p>        return (void*)0;<br>} </p> <p>int main()<br>{<br>        char* pArg = "hello";<br>        pthread_t tid;<br>        pthread_create(&tid,NULL,thread_handler,pArg);</p> <p>        printf("main thread id = %u\n",pthread_self());<br>        sleep(2);</p> <p>        printf("killing now\n");<br>        pthread_kill(tid,SIGQUIT);</p> <p>        sleep(20);</p> <p>        printf("exit main now\n");</p> <p>        return 0;<br>}<br>~<br>~<br>~<br>~<br>"test.cpp" 42L, 648C written<br>[tqg@localhost test]$ g++ -o test test.cpp -lpthread<br>[tqg@localhost test]$ ./test <br>main thread id = 3086875296<br>thread arg = hello<br>killing now<br>catch signal: 3,thread id = 3086871472<br>exit main now<br>[tqg@localhost test]$ <br><br>可以看出Q信号处理函数的执行是在要捕获信L子线Ethread_handler的上下文中执行的?/p> <img src ="http://www.shnenglu.com/true/aggbug/72072.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/true/" target="_blank">true</a> 2009-01-15 11:39 <a href="http://www.shnenglu.com/true/archive/2009/01/15/72072.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>用GDB调试E序---转脓Q非常全面的调试技?/title><link>http://www.shnenglu.com/true/archive/2009/01/11/71749.html</link><dc:creator>true</dc:creator><author>true</author><pubDate>Sun, 11 Jan 2009 12:21:00 GMT</pubDate><guid>http://www.shnenglu.com/true/archive/2009/01/11/71749.html</guid><wfw:comment>http://www.shnenglu.com/true/comments/71749.html</wfw:comment><comments>http://www.shnenglu.com/true/archive/2009/01/11/71749.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/true/comments/commentRss/71749.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/true/services/trackbacks/71749.html</trackback:ping><description><![CDATA[用GDB调试E序 <br>GDB是一个强大的命o行调试工兗大家知道命令行的强大就是在于,其可以Ş成执行序<br>列,形成脚本。UNIX下的软g全是命o行的Q这l程序开发提代供了极大的便利Q命令行<br>软g的优势在于,它们可以非常Ҏ的集成在一P使用几个单的已有工具的命令,可<br>以做Z个非常强大的功能?<br>于是UNIX下的软g比Windows下的软g更能有机地结合,各自发挥各自的长处,l合?br>更ؓ强劲的功能。而Windows下的囑Ş软g基本上是各自Q互怸能调用,很不利于<br>各种软g的相互集成。在q里q不是要和Windows做个什么比较,所?#8220;寸有所长,有<br>所?#8221;Q图形化工具q是有不如命令行的地斏V?<br>用GDB调试E序 <br>GDB概述 <br>———?<br>GDB是GNU开源组l发布的一个强大的UNIX下的E序调试工具。或许,各位比较喜欢?br>U图形界面方式的Q像VC、BCB{IDE的调试,但如果你是在UNIXq_下做软gQ你<br>会发现GDBq个调试工具有比VC、BCB的图形化调试器更强大的功能。所?#8220;寸有所长,<br>有所?#8221;是q个道理?<br>一般来_GDB主要帮忙你完成下面四个方面的功能Q?<br>1、启动你的程序,可以按照你的自定义的要求随心所Ʋ的q行E序?<br>2、可让被调试的程序在你所指定的调|的断点处停住。(断点可以是条件表辑ּQ?<br>3、当E序被停住时Q可以检查此时你的程序中所发生的事?<br>4、动态的改变你程序的执行环境?<br>从上面看来,GDB和一般的调试工具没有什么两P基本上也是完成这些功能,不过在细<br>节上Q你会发现GDBq个调试工具的强大,大家可能比较习惯了图形化的调试工P但有<br>时候,命o行的调试工具却有着囑Ş化工h不能完成的功能。让我们一一看来?<br>一个调试示?<br>—————?<br>源程序:tst.c <br>1 #include <br>2 <br>3 int func(int n) <br>4 { <br>5 int sum=0,i; <br>6 for(i=0; i<7; i++) { <p>8 sum+=i; <br>9 } <br>10 return sum; <br>11 } <br>12 <br>13 <br>14 main() <br>15 { <br>16 int i; <br>17 long result = 0; <br>18 for(i=1; i<=100; i++) <br>19 { <br>20 result += i; <br>21 } <br>22 <br>23 printf("result[1-100] = %d \n", result ); <br>24 printf("result[1-250] = %d \n", func(250) ); <br>25 } <br>~译生成执行文gQ(Linux下) <br>hchen/test> cc -g tst.c -o tst <br>使用GDB调试Q?<br>hchen/test> gdb tst <---------- 启动GDB <br>GNU gdb 5.1.1 <br>Copyright 2002 Free Software Foundation, Inc. <br>GDB is free software, covered by the GNU General Public License, and you are <br>welcome to change it and/or distribute copies of it under certain conditions. <br>Type "show copying" to see the conditions. <br>There is absolutely no warranty for GDB. Type "show warranty" for details. <br>This GDB was configured as "i386-suse-linux"... <br>(gdb) l <-------------------- l命o相当于listQ从W一行开始例出原码?<br>1 #include <br>2 <br>3 int func(int n) <br>4 { <br>5 int sum=0,i; <br>6 for(i=0; i 7 { <br>8 sum+=i; <br>9 } <br>10 return sum; <br>(gdb) <-------------------- 直接回R表示Q重复上一ơ命?<br>11 } </p> <p>12 <br>13 <br>14 main() <br>15 { <br>16 int i; <br>17 long result = 0; <br>18 for(i=1; i<=100; i++) <br>19 { <br>20 result += i; <br>(gdb) break 16 <-------------------- 讄断点Q在源程序第16行处?<br>Breakpoint 1 at 0x8048496: file tst.c, line 16. <br>(gdb) break func <-------------------- 讄断点Q在函数func()入口处?<br>Breakpoint 2 at 0x8048456: file tst.c, line 5. <br>(gdb) info break <-------------------- 查看断点信息?<br>Num Type Disp Enb Address What <br>1 breakpoint keep y 0x08048496 in main at tst.c:16 <br>2 breakpoint keep y 0x08048456 in func at tst.c:5 <br>(gdb) r <--------------------- q行E序Qrun命o?<br>Starting program: /home/hchen/test/tst <br>Breakpoint 1, main () at tst.c:17 <---------- 在断点处停住?<br>17 long result = 0; <br>(gdb) n <--------------------- 单条语句执行Qnext命o写?<br>18 for(i=1; i<=100; i++) <br>(gdb) n <br>20 result += i; <br>(gdb) n <br>18 for(i=1; i<=100; i++) <br>(gdb) n <br>20 result += i; <br>(gdb) c <--------------------- l箋q行E序Qcontinue命o写?<br>Continuing. <br>result[1-100] = 5050 <----------E序输出?<br>Breakpoint 2, func (n=250) at tst.c:5 <br>5 int sum=0,i; <br>(gdb) n <br>6 for(i=1; i<=n; i++) <br>(gdb) p i <--------------------- 打印变量i的|print命o写?<br>$1 = 134513808 <br>(gdb) n <br>8 sum+=i; <br>(gdb) n <br>6 for(i=1; i<=n; i++) </p> <p>(gdb) p sum <br>$2 = 1 <br>(gdb) n <br>8 sum+=i; <br>(gdb) p i <br>$3 = 2 <br>(gdb) n <br>6 for(i=1; i<=n; i++) <br>(gdb) p sum <br>$4 = 3 <br>(gdb) bt <--------------------- 查看函数堆栈?<br>#0 func (n=250) at tst.c:5 <br>#1 0x080484e4 in main () at tst.c:24 <br>#2 0x400409ed in __libc_start_main () from /lib/libc.so.6 <br>(gdb) finish <--------------------- 退出函数?<br>Run till exit from #0 func (n=250) at tst.c:5 <br>0x080484e4 in main () at tst.c:24 <br>24 printf("result[1-250] = %d \n", func(250) ); <br>Value returned is $6 = 31375 <br>(gdb) c <--------------------- l箋q行?<br>Continuing. <br>result[1-250] = 31375 <----------E序输出?<br>Program exited with code 027. <--------E序退出,调试l束?<br>(gdb) q <--------------------- 退出gdb?<br>hchen/test> <br>好了Q有了以上的感性认识,q是让我们来pȝ地认识一下gdb吧?<br>使用GDB <br>———?<br>一般来说GDB主要调试的是C/C++的程序。要调试C/C++的程序,首先在编译时Q我们必<br>要把调试信息加到可执行文g中。用编译器Qcc/gcc/g++Q的 -g 参数可以做到q一炏V?br>如: <br>> cc -g hello.c -o hello <br>> g++ -g hello.cpp -o hello <br>如果没有-gQ你看不见E序的函数名、变量名Q所代替的全是运行时的内存地址。当你用<br>-g把调试信息加入之后,q成功编译目标代码以后,让我们来看看如何用gdb来调试他?<br>启动GDB的方法有以下几种Q?</p> <p>1、gdb <br>program也就是你的执行文Ӟ一般在当然目录下?<br>2、gdb core <br>用gdb同时调试一个运行程序和core文gQcore是程序非法执行后core dump后生的文g?<br>3、gdb <br>如果你的E序是一个服务程序,那么你可以指定这个服务程序运行时的进EID。gdb会自<br>动attach上去Qƈ调试他。program应该在PATH环境变量中搜索得到?<br>GDB启动Ӟ可以加上一些GDB的启动开养I详细的开兛_以用gdb -help查看。我在下<br>面只例D一些比较常用的参数Q?<br>-symbols <br>-s <br>从指定文件中dW号表?<br>-se file <br>从指定文件中dW号表信息,q把他用在可执行文g中?<br>-core <br>-c <br>调试时core dump的core文g?<br>-directory <br>-d <br>加入一个源文g的搜索\径。默认搜索\径是环境变量中PATH所定义的\径?<br>GDB的命令概?<br>——————?<br>启动gdb后,׃被带入gdb的调试环境中Q就可以使用gdb的命令开始调试程序了Qgdb<br>的命令可以用help命o来查看,如下所C: <br>/home/hchen> gdb <br>GNU gdb 5.1.1 <br>Copyright 2002 Free Software Foundation, Inc. <br>GDB is free software, covered by the GNU General Public License, and you are <br>welcome to change it and/or distribute copies of it under certain conditions. <br>Type "show copying" to see the conditions. <br>There is absolutely no warranty for GDB. Type "show warranty" for details. <br>This GDB was configured as "i386-suse-linux". <br>(gdb) help </p> <p>List of classes of commands: <br>aliases -- Aliases of other commands <br>breakpoints -- Making program stop at certain points <br>data -- Examining data <br>files -- Specifying and examining files <br>internals -- Maintenance commands <br>obscure -- Obscure features <br>running -- Running the program <br>stack -- Examining the stack <br>status -- Status inquiries <br>support -- Support facilities <br>tracepoints -- Tracing of program execution without stopping the program <br>user-defined -- User-defined commands <br>Type "help" followed by a class name for a list of commands in that class. <br>Type "help" followed by command name for full documentation. <br>Command name abbreviations are allowed if unambiguous. <br>(gdb) <br>gdb的命令很多,gdb把之分成许多个种cRhelp命o只是例出gdb的命令种c,如果要看<br>U类中的命oQ可以用help 命oQ如Qhelp breakpointsQ查看设|断点的所有命令。也<br>可以直接help 来查看命令的帮助?<br>gdb中,输入命oӞ可以不用打全命oQ只用打命o的前几个字符可以了Q当Ӟ命o<br>的前几个字符应该要标志着一个唯一的命令,在Linux下,你可以敲MơTAB键来补齐<br>命o的全Uͼ如果有重复的Q那么gdb会把其例出来?<br>CZ一Q在q入函数funcӞ讄一个断炏V可以敲入break funcQ或是直接就是b func <br>(gdb) b func <br>Breakpoint 1 at 0x8048458: file hello.c, line 10. <br>CZ二:敲入b按两ơTAB键,你会看到所有b打头的命令: <br>(gdb) b <br>backtrace break bt <br>(gdb) <br>CZ三:只记得函数的前缀Q可以这P <br>(gdb) b make_ <按TAB?gt; <br>Q再按下一ơTAB键,你会看到:Q?<br>make_a_section_from_file make_environ <br>make_abs_section make_function_type <br>make_blockvector make_pointer_type </p> <p>make_cleanup make_reference_type <br>make_command make_symbol_completion_list <br>(gdb) b make_ <br>GDB把所有make开头的函数全部例出来给你查看?<br>CZ四:调试C++的程序时Q有可以函数名一栗如Q?<br>(gdb) b 'bubble( M-? <br>bubble(double,double) bubble(int,int) <br>(gdb) b 'bubble( <br>你可以查看到C++中的所有的重蝲函数及参数。(注:M-??#8220;按两ơTAB?#8221;是一个意思) <br>要退出gdbӞ只用发quit或命令简Uqp了?<br>GDB中运行UNIX的shellE序 <br>———————————?<br>在gdb环境中,你可以执行UNIX的shell的命令,使用gdb的shell命o来完成: <br>shell <br>调用UNIX的shell来执行,环境变量SHELL中定义的UNIX的shell会被用来执行,?br>果SHELL没有定义Q那׃用UNIX的标准shellQ?bin/sh。(在Windows中用Command.com<br>或cmd.exeQ?<br>q有一个gdb命o是makeQ?<br>make <br>可以在gdb中执行make命o来重新build自己的程序。这个命令等价于“shell make ”?<br>在GDB中运行程?<br>———————?<br>当以gdb 方式启动gdb后,gdb会在PATH路径和当前目录中搜烦的源文g。如要确认gdb<br>是否d源文Ӟ可用l或list命oQ看看gdb是否能列出源代码?<br>在gdb中,q行E序使用r或是run命o。程序的q行Q你有可能需要设|下面四斚w的事?<br>1、程序运行参数?<br>set args 可指定运行时参数。(如:set args 10 20 30 40 50Q?<br>show args 命o可以查看讄好的q行参数?<br>2、运行环境?<br>path <br>可设定程序的q行路径?<br>show paths 查看E序的运行\径?</p> <p>set environment varname [=value] 讄环境变量。如Qset env USER=hchen <br>show environment [varname] 查看环境变量?<br>3、工作目录?<br>cd <br>相当于shell的cd命o?<br>pwd 昄当前的所在目录?<br>4、程序的输入输出?<br>info terminal 昄你程序用到的l端的模式?<br>使用重定向控制程序输出。如Qrun > outfile <br>tty命o可以指写输入输出的终端设备。如Qtty /dev/ttyb <br>调试已运行的E序 <br>———————?<br>两种ҎQ?<br>1、在UNIX下用ps查看正在q行的程序的PIDQ进EIDQ,然后用gdb PID格式挂接正在<br>q行的程序?<br>2、先用gdb 兌上源代码Qƈq行gdbQ在gdb中用attach命o来挂接进E的PID。ƈ?br>detach来取消挂接的q程?<br>暂停 / 恢复E序q行 <br>————————?<br>调试E序中,暂停E序q行是必ȝQGDB可以方便地暂停程序的q行。你可以讄E序<br>的在哪行停住Q在什么条件下停住Q在收到什么信h停往{等。以便于你查看运行时的变<br>量,以及q行时的程?<br>当进E被gdb停住Ӟ你可以用info program 来查看程序的是否在运行,q程P被暂?br>的原因?<br>在gdb中,我们可以有以下几U暂停方式:断点QBreakPointQ、观察点QWatchPointQ、捕<br>捉点QCatchPointQ、信PSignalsQ、线E停止(Thread StopsQ。如果要恢复E序q行Q可<br>以用c或是continue命o?<br>一、设|断点(BreakPointQ?<br>我们用break命o来设|断炏V正面有几点讄断点的方法: <br>break <br>在进入指定函数时停住。C++中可以用class::function或function(type,type)格式来指定函</p> <p>数名?<br>break <br>在指定行号停住?<br>break +offset <br>break -offset <br>在当前行L前面或后面的offset行停住。offiset然数?<br>break filename:linenum <br>在源文gfilename的linenum行处停住?<br>break filename:function <br>在源文gfilename的function函数的入口处停住?<br>break *address <br>在程序运行的内存地址处停住?<br>break <br>break命o没有参数Ӟ表示在下一条指令处停住?<br>break ... if <br>...可以是上q的参数Qcondition表示条gQ在条g成立时停住。比如在循环境体中,可以?br>|break if i=100Q表C当i?00时停住程序?<br>查看断点Ӟ可用info命oQ如下所C:Q注Qn表示断点P <br>info breakpoints [n] <br>info break [n] <br>二、设|观察点QWatchPointQ?<br>观察点一般来观察某个表达式(变量也是一U表辑ּQ的值是否有变化了,如果有变化,?br>上停住程序。我们有下面的几U方法来讄观察点: <br>watch <br>辑ּQ变量)expr讄一个观察点。一量表辑ּ值有变化Ӟ马上停住E序?<br>rwatch <br>当表辑ּQ变量)expr被读Ӟ停住E序?<br>awatch <br>当表辑ּQ变量)的DL被写Ӟ停住E序?</p> <p>info watchpoints <br>列出当前所讄了的所有观察点?<br>三、设|捕捉点QCatchPointQ?<br>你可讄捕捉Ҏ补捉E序q行时的一些事件。如Q蝲入共享库Q动态链接库Q或是C++<br>的异常。设|捕捉点的格式ؓQ?<br>catch <br>当event发生Ӟ停住E序。event可以是下面的内容Q?<br>1、throw 一个C++抛出的异常。(throw为关键字Q?<br>2、catch 一个C++捕捉到的异常。(catch为关键字Q?<br>3、exec 调用pȝ调用exec时。(exec为关键字Q目前此功能只在HP-UX下有用) <br>4、fork 调用pȝ调用fork时。(fork为关键字Q目前此功能只在HP-UX下有用) <br>5、vfork 调用pȝ调用vfork时。(vfork为关键字Q目前此功能只在HP-UX下有用) <br>6、load ?load 载入׃n库(动态链接库Q时。(load为关键字Q目前此功能只在HP-UX<br>下有用) <br>7、unload ?unload 卸蝲׃n库(动态链接库Q时。(unload为关键字Q目前此功能只在<br>HP-UX下有用) <br>tcatch <br>只设|一ơ捕捉点Q当E序停住以后Q应点被自动删除?<br>四、维护停止点 <br>上面说了如何讄E序的停止点QGDB中的停止点也是上述的三cR在GDB中,如果?br>觉得已定义好的停止点没有用了Q你可以使用delete、clear、disable、enableq几个命令来<br>q行l护?<br>clear <br>清除所有的已定义的停止炏V?<br>clear <br>clear <br>清除所有设|在函数上的停止炏V?<br>clear <br>clear <br>清除所有设|在指定行上的停止点?<br>delete [breakpoints] [range...] <br>删除指定的断点,breakpoints为断点号。如果不指定断点P则表C删除所有的断点。range <br>表示断点L范围Q如Q?-7Q。其写命令ؓd?</p> <p>比删除更好的一U方法是disable停止点,disable了的停止点,GDB不会删除Q当你还需?br>Ӟenable卛_Q就好像回收站一栗?<br>disable [breakpoints] [range...] <br>disable所指定的停止点Qbreakpoints为停止点受如果什么都不指定,表示disable所有的<br>停止炏V简写命令是dis. <br>enable [breakpoints] [range...] <br>enable所指定的停止点Qbreakpoints为停止点受?<br>enable [breakpoints] once range... <br>enable所指定的停止点一ơ,当程序停止后Q该停止炚w上被GDB自动disable?<br>enable [breakpoints] delete range... <br>enable所指定的停止点一ơ,当程序停止后Q该停止炚w上被GDB自动删除?<br>五、停止条件维?<br>前面在说到设|断ҎQ我们提到过可以讄一个条Ӟ当条件成立时Q程序自动停止,q?br>是一个非常强大的功能Q这里,我想专门说说q个条g的相关维护命令。一般来_为断?br>讄一个条Ӟ我们使用if关键词,后面跟其断点条g。ƈ且,条g讄好后Q我们可?br>用condition命o来修Ҏ点的条g。(只有break和watch命o支持ifQcatch目前暂不支持<br>ifQ?<br>condition <br>修改断点号ؓbnum的停止条件ؓexpression?<br>condition <br>清除断点号ؓbnum的停止条件?<br>q有一个比较特D的l护命oignoreQ你可以指定E序q行Ӟ忽略停止条g几次?<br>ignore <br>表示忽略断点号ؓbnum的停止条件countơ?<br>六、ؓ停止点设定运行命?<br>我们可以使用GDB提供的command命o来设|停止点的运行命令。也是_当运行的<br>E序在被停止住时Q我们可以让其自动运行一些别的命令,q很有利行自动化调试。对Z<br>GDB的自动化调试是一个强大的支持?<br>commands [bnum] </p> <p>... command-list ... <br>end <br>为断点号bnum指写一个命令列表。当E序被该断点停住Ӟgdb会依ơ运行命令列表中?br>命o?<br>例如Q?<br>break foo if x>0 <br>commands <br>printf "x is %d\n",x <br>continue <br>end <br>断点讄在函数foo中,断点条g是x>0Q如果程序被断住后,也就是,一旦x的值在foo<br>函数中大?QGDB会自动打印出x的|ql运行程序?<br>如果你要清除断点上的命o序列Q那么只要简单的执行一下commands命oQƈ直接在打?br>endp了?<br>七、断点菜?<br>在C++中,可能会重复出现同一个名字的函数若干ơ(函数重蝲Q,在这U情况下Qbreak ?br>能告诉GDB要停在哪个函数的入口。当Ӟ你可以用break 也就是把函数的参数类型告<br>诉GDBQ以指定一个函数。否则的话,GDB会给你列Z个断点菜单供你选择你所需要的<br>断点。你只要输入你菜单列表中的编号就可以了。如Q?<br>(gdb) b String::after <br>[0] cancel <br>[1] all <br>[2] file:String.cc; line number:867 <br>[3] file:String.cc; line number:860 <br>[4] file:String.cc; line number:875 <br>[5] file:String.cc; line number:853 <br>[6] file:String.cc; line number:846 <br>[7] file:String.cc; line number:735 <br>> 2 4 6 <br>Breakpoint 1 at 0xb26c: file String.cc, line 867. <br>Breakpoint 2 at 0xb344: file String.cc, line 875. <br>Breakpoint 3 at 0xafcc: file String.cc, line 846. <br>Multiple breakpoints were set. <br>Use the "delete" command to delete unwanted <br>breakpoints. <br>(gdb) </p> <p>可见QGDB列出了所有after的重载函敎ͼ你可以选一下列表编号就行了?表示攑ּ讄<br>断点Q?表示所有函数都讄断点?<br>八、恢复程序运行和单步调试 <br>当程序被停住了,你可以用continue命o恢复E序的运行直到程序结束,或下一个断点到来?br>也可以用step或next命o单步跟踪E序?<br>continue [ignore-count] <br>c [ignore-count] <br>fg [ignore-count] <br>恢复E序q行Q直到程序结束,或是下一个断点到来。ignore-count表示忽略其后的断Ҏ<br>数。continueQcQfg三个命o都是一L意思?<br>step <br>单步跟踪Q如果有函数调用Q他会进入该函数。进入函数的前提是,此函数被~译有debug<br>信息。很像VC{工具中的step in。后面可以加count也可以不加,不加表示一条条地执行,<br>加表C执行后面的count条指令,然后再停住?<br>next <br>同样单步跟踪Q如果有函数调用Q他不会q入该函数。很像VC{工具中的step over。后?br>可以加count也可以不加,不加表示一条条地执行,加表C执行后面的count条指令,然后<br>再停住?<br>set step-mode <br>set step-mode on <br>打开step-mode模式Q于是,在进行单步跟t时Q程序不会因为没有debug信息而不停住?br>q个参数有很利于查看机器码?<br>set step-mod off <br>关闭step-mode模式?<br>finish <br>q行E序Q直到当前函数完成返回。ƈ打印函数q回时的堆栈地址和返回值及参数值等信息?<br>until ?u <br>当你厌倦了在一个@环体内单步跟t时Q这个命令可以运行程序直到退出@环体?<br>stepi ?si <br>nexti ?ni <br>单步跟踪一条机器指令!一条程序代码有可能由数条机器指令完成,stepi和nexti可以单步<br>执行机器指o。与之一h相同功能的命令是“display/i $pc” Q当q行完这个命令后Q单<br>步跟t会在打出程序代码的同时打出机器指oQ也是汇编代码Q?</p> <p>九、信PSignalsQ?<br>信号是一UY中断Q是一U处理异步事件的Ҏ。一般来_操作pȝ都支持许多信受尤<br>其是UNIXQ比较重要应用程序一般都会处理信受UNIX定义了许多信P比如SIGINT<br>表示中断字符信号Q也是Ctrl+C的信PSIGBUS表示g故障的信PSIGCHLD表示<br>子进E状态改变信PSIGKILL表示l止E序q行的信P{等。信号量~程是UNIX?br>非常重要的一U技术?<br>GDB有能力在你调试程序的时候处理Q何一U信P你可以告诉GDB需要处理哪一U信<br>受你可以要求GDB收到你所指定的信hQ马上停住正在运行的E序Q以供你q行调试?br>你可以用GDB的handle命o来完成这一功能?<br>handle <br>在GDB中定义一个信号处理。信号可以以SIG开头或不以SIG开_可以用定义一个要?br>理信L范围Q如QSIGIO-SIGKILLQ表C处理从SIGIO信号到SIGKILL的信P其中?br>括SIGIOQSIGIOTQSIGKILL三个信号Q,也可以用关键字all来标明要处理所有的信号?br>一旦被调试的程序接收到信号Q运行程序马上会被GDB停住Q以供调试。其可以是以下几<br>U关键字的一个或多个?<br>nostop <br>当被调试的程序收ChQGDB不会停住E序的运行,但会打出消息告诉你收到这U信<br>受?<br>stop <br>当被调试的程序收ChQGDB会停住你的程序?<br>print <br>当被调试的程序收ChQGDB会显C出一条信息?<br>noprint <br>当被调试的程序收ChQGDB不会告诉你收CL信息?<br>pass <br>noignore <br>当被调试的程序收ChQGDB不处理信受这表示QGDB会把q个信号交给被调试程<br>序会处理?<br>nopass <br>ignore <br>当被调试的程序收ChQGDB不会让被调试E序来处理这个信受?<br>info signals <br>info handle <br>查看有哪些信号在被GDB中?<br>十、线E(Thread StopsQ?</p> <p>如果你程序是多线E的话,你可以定义你的断Ҏ否在所有的U程上,或是在某个特定的U?br>E。GDB很容易帮你完成这一工作?<br>break thread <br>break thread if ... <br>linespec指定了断点设|在的源E序的行受threadno指定了线E的IDQ注意,q个ID?br>GDB分配的,你可以通过“info threads”命o来查看正在运行程序中的线E信息。如果你<br>不指定thread 则表CZ的断点设在所有线E上面。你q可以ؓ某线E指定断Ҏ件。如Q?<br>(gdb) break frik.c:13 thread 28 if bartab > lim <br>当你的程序被GDB停住Ӟ所有的q行U程都会被停住。这方便你你查看q行E序的M<br>情况。而在你恢复程序运行时Q所有的U程也会被恢复运行。那怕是主进E在被单步调试时?<br>查看栈信?<br>————?<br>当程序被停住了,你需要做的第一件事是查看E序是在哪里停住的。当你的E序调用了一<br>个函敎ͼ函数的地址Q函数参敎ͼ函数内的局部变量都会被压入“?#8221;QStackQ中。你可以<br>用GDB命o来查看当前的栈中的信息?<br>下面是一些查看函数调用栈信息的GDB命oQ?<br>backtrace <br>bt <br>打印当前的函数调用栈的所有信息。如Q?<br>(gdb) bt <br>#0 func (n=250) at tst.c:6 <br>#1 0x08048524 in main (argc=1, argv=0xbffff674) at tst.c:30 <br>#2 0x400409ed in __libc_start_main () from /lib/libc.so.6 <br>从上可以看出函数的调用栈信息Q__libc_start_main --> main() --> func() <br>backtrace <br>bt <br>n是一个正整数Q表C只打印栈顶上n层的栈信息?<br>backtrace <-n> <br>bt <-n> <br>-n表一个负整数Q表C只打印栈底下n层的栈信息?<br>如果你要查看某一层的信息Q你需要在切换当前的栈Q一般来_E序停止Ӟ最层的栈</p> <p>是当前栈,如果你要查看栈下面层的详l信息,首先要做的是切换当前栈?<br>frame <br>f <br>n是一个从0开始的整数Q是栈中的层~号。比如:frame 0Q表C栈Ӟframe 1Q表C栈?br>W二层?<br>up <br>表示向栈的上面移动n层,可以不打nQ表C向上移动一层?<br>down <br>表示向栈的下面移动n层,可以不打nQ表C向下移动一层?<br>上面的命令,都会打印出移动到的栈层的信息。如果你不想让其打出信息。你可以使用q三<br>个命令: <br>select-frame 对应?frame 命o?<br>up-silently 对应?up 命o?<br>down-silently 对应?down 命o?<br>查看当前栈层的信息,你可以用以下GDB命oQ?<br>frame ?f <br>会打印出q些信息Q栈的层~号Q当前的函数名,函数参数|函数所在文件及行号Q函?br>执行到的语句?<br>info frame <br>info f <br>q个命o会打印出更ؓ详细的当前栈层的信息Q只不过Q大多数都是q行时的内内地址。比<br>如:函数地址Q调用函数的地址Q被调用函数的地址Q目前的函数是由什么样的程序语a?br>成的、函数参数地址及倹{局部变量的地址{等。如Q?<br>(gdb) info f <br>Stack level 0, frame at 0xbffff5d4: <br>eip = 0x804845d in func (tst.c:6); saved eip 0x8048524 <br>called by frame at 0xbffff60c <br>source language c. <br>Arglist at 0xbffff5d4, args: n=250 <br>Locals at 0xbffff5d4, Previous frame's sp is 0x0 <br>Saved registers: <br>ebp at 0xbffff5d4, eip at 0xbffff5d8 <br>info args </p> <p>打印出当前函数的参数名及其倹{?<br>info locals <br>打印出当前函C所有局部变量及其倹{?<br>info catch <br>打印出当前的函数中的异常处理信息?<br>查看源程?<br>————?<br>一、显C源代码 <br>GDB 可以打印出所调试E序的源代码Q当Ӟ在程序编译时一定要加上-g的参敎ͼ把源E?br>序信息编译到执行文g中。不然就看不到源E序了。当E序停下来以后,GDB会报告程?br>停在了那个文件的W几行上。你可以用list命o来打印程序的源代码。还是来看一看查看源<br>代码的GDB命o吧?<br>list <br>昄E序Wlinenum行的周围的源E序?<br>list <br>昄函数名ؓfunction的函数的源程序?<br>list <br>昄当前行后面的源程序?<br>list - <br>昄当前行前面的源程序?<br>一般是打印当前行的?行和?行,如果昄函数是是?行下8行,默认?0行,?br>Ӟ你也可以定制昄的范_使用下面命o可以讄一ơ显C源E序的行数?<br>set listsize <br>讄一ơ显C源代码的行数?<br>show listsize <br>查看当前listsize的设|?<br>list命oq有下面的用法: <br>list , </p> <p>昄从first行到last行之间的源代码?<br>list , <br>昄从当前行到last行之间的源代码?<br>list + <br>往后显C源代码?<br>一般来说在list后面可以跟以下这们的参数Q?<br>行号?<br><+offset> 当前行号的正偏移量?<br><-offset> 当前行号的负偏移量?<br>哪个文g的哪一行?<br>函数名?<br>哪个文g中的哪个函数?<br><*address> E序q行时的语句在内存中的地址?<br>二、搜索源代码 <br>不仅如此QGDBq提供了源代码搜索的命oQ?<br>forward-search <br>search <br>向前面搜索?<br>reverse-search <br>全部搜烦?<br>其中Q就是正则表辑ּQ也M个字W串的匹配模式,关于正则表达式,我就不在q里讲了Q?br>q请各位查看相关资料?<br>三、指定源文g的\?<br>某些时候,?g~译q后的执行程序中只是包括了源文g的名字,没有路径名。GDB提供<br>了可以让你指定源文g的\径的命oQ以便GDBq行搜烦?<br>directory <br>dir <br>加一个源文g路径到当前\径的前面。如果你要指定多个\径,UNIX下你可以使用“:”Q?br>Windows下你可以使用“;”?</p> <p>directory <br>清除所有的自定义的源文件搜索\径信息?<br>show directories <br>昄定义了的源文件搜索\径?<br>四、源代码的内?<br>你可以用info line命o来查看源代码在内存中的地址。info line后面可以?#8220;行号”Q?#8220;?br>数名”Q?#8220;文g?行号”Q?#8220;文g?函数?#8221;Q这个命令会打印出所指定的源码在q行时的?br>存地址Q如Q?<br>(gdb) info line tst.c:func <br>Line 5 of "tst.c" starts at address 0x8048456 and ends at 0x804845d . <br>q有一个命令(disassembleQ你可以查看源程序的当前执行时的机器码,q个命o会把目前<br>内存中的指odump出来。如下面的示例表C查看函数func的汇~代码?<br>(gdb) disassemble func <br>Dump of assembler code for function func: <br>0x8048450 : push %ebp <br>0x8048451 : mov %esp,%ebp <br>0x8048453 : sub $0x18,%esp <br>0x8048456 : movl $0x0,0xfffffffc(%ebp) <br>0x804845d : movl $0x1,0xfffffff8(%ebp) <br>0x8048464 : mov 0xfffffff8(%ebp),%eax <br>0x8048467 : cmp 0x8(%ebp),%eax <br>0x804846a : jle 0x8048470 <br>0x804846c : jmp 0x8048480 <br>0x804846e : mov %esi,%esi <br>0x8048470 : mov 0xfffffff8(%ebp),%eax <br>0x8048473 : add %eax,0xfffffffc(%ebp) <br>0x8048476 : incl 0xfffffff8(%ebp) <br>0x8048479 : jmp 0x8048464 <br>0x804847b : nop <br>0x804847c : lea 0x0(%esi,1),%esi <br>0x8048480 : mov 0xfffffffc(%ebp),%edx <br>0x8048483 : mov %edx,%eax <br>0x8048485 : jmp 0x8048487 <br>0x8048487 : mov %ebp,%esp <br>0x8048489 : pop %ebp <br>0x804848a : ret <br>End of assembler dump. </p> <p>查看q行时数?<br>——————?<br>在你调试E序Ӟ当程序被停住Ӟ你可以用print命oQ简写命令ؓpQ,或是同义命o<br>inspect来查看当前程序的q行数据。print命o的格式是Q?<br>print <br>print / <br>是表辑ּQ是你所调试的程序的语言的表辑ּQGDB可以调试多种~程语言Q,是输出的?br>式,比如Q如果要把表辑ּ?6q制的格式输出,那么是/x?<br>一、表辑ּ <br>print和许多GDB的命令一P可以接受一个表辑ּQGDB会根据当前的E序q行的数?br>来计这个表辑ּQ既然是表达式,那么可以是当前E序q行中的const帔R、变量、函<br>数等内容。可惜的是GDB不能使用你在E序中所定义的宏?<br>表达式的语法应该是当前所调试的语a的语法,׃C/C++是一U大众型的语aQ所以,?br>文中的例子都是关于C/C++的。(而关于用GDB调试其它语言的章节,我将在后面介l) <br>在表辑ּ中,有几UGDB所支持的操作符Q它们可以用在Q何一U语a中?<br>@ <br>是一个和数组有关的操作符Q在后面会有更详l的说明?<br>:: <br>指定一个在文g或是一个函C的变量?<br>{} <br>表示一个指向内存地址的类型ؓtype的一个对象?<br>二、程序变?<br>在GDB中,你可以随时查看以下三U变量的| <br>1、全局变量Q所有文件可见的Q?<br>2、静态全局变量Q当前文件可见的Q?<br>3、局部变量(当前Scope可见的) <br>如果你的局部变量和全局变量发生冲突Q也是重名Q,一般情况下是局部变量会隐藏全局<br>变量Q也是_如果一个全局变量和一个函C的局部变量同名时Q如果当前停止点在函</p> <p>CQ用print昄出的变量的g是函C的局部变量的倹{如果此时你x看全局变量<br>的值时Q你可以使用“::”操作W: <br>file::variable <br>function::variable <br>可以通过q种形式指定你所x看的变量Q是哪个文g中的或是哪个函数中的。例如,查看<br>文gf2.c中的全局变量x的| <br>gdb) p 'f2.c'::x <br>当然Q?#8220;::”操作W会和C++中的发生冲突QGDB能自动识?#8220;::” 是否C++的操作符Q所<br>以你不必担心在调试C++E序时会出现异常?<br>另外Q需要注意的是,如果你的E序~译时开启了优化选项Q那么在用GDB调试被优化过<br>的程序时Q可能会发生某些变量不能讉KQ或是取值错误码的情c这个是很正常的Q因?br>优化E序会删改你的程序,整理你程序的语句序Q剔除一些无意义的变量等Q所以在GDB<br>调试q种E序Ӟq行时的指o和你所~写指o有不一P也就会出C所惌不到的结<br>果。对付这U情冉|Q需要在~译E序时关闭编译优化。一般来_几乎所有的~译器都?br>持编译优化的开养I例如QGNU的C/C++~译器GCCQ你可以使用“-gstabs”选项来解?br>q个问题。关于编译器的参敎ͼq请查看~译器的使用说明文档?<br>三、数l?<br>有时候,你需要查看一D连l的内存I间的倹{比如数l的一D,或是动态分配的数据的大<br>。你可以使用GDB?#8220;@”操作W,“@”的左ҎW一个内存的地址的|“@”的右<br>边则你你x看内存的长度。例如,你的E序中有q样的语句: <br>int *array = (int *) malloc (len * sizeof (int)); <br>于是Q在GDB调试q程中,你可以以如下命o昄个动态数l的取| <br>p <a href="mailto:*array@len"><font color=#336699>*array@len</font></a> <br>@的左Ҏ数组的首地址的|也就是变量array所指向的内容,双则是数据的长度,?br>保存在变量len中,其输出结果,大约是下面这个样子的Q?<br>(gdb) p <a href="mailto:*array@len"><font color=#336699>*array@len</font></a> <br>$1 = {2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40} <br>如果是静态数l的话,可以直接用print数组名,可以显C数l中所有数据的内容了?<br>四、输出格?</p> <p>一般来_GDB会根据变量的cd输出变量的倹{但你也可以自定义GDB的输出的格式?br>例如Q你惌Z个整数的十六q制Q或是二q制来查看这个整型变量的中的位的情况。要<br>做到q样Q你可以使用GDB的数据显C格式: <br>x 按十六进制格式显C变量?<br>d 按十q制格式昄变量?<br>u 按十六进制格式显C无W号整型?<br>o 按八q制格式昄变量?<br>t 按二q制格式昄变量?<br>a 按十六进制格式显C变量?<br>c 按字W格式显C变量?<br>f 按QҎ格式昄变量?<br>(gdb) p i <br>$21 = 101 <br>(gdb) p/a i <br>$22 = 0x65 <br>(gdb) p/c i <br>$23 = 101 'e' <br>(gdb) p/f i <br>$24 = 1.41531145e-43 <br>(gdb) p/x i <br>$25 = 0x65 <br>(gdb) p/t i <br>$26 = 1100101 <br>五、查看内?<br>你可以用examine命oQ简写是xQ来查看内存地址中的倹{x命o的语法如下所C: <br>x/ <br>n、f、u是可选的参数?<br>n 是一个正整数Q表C显C内存的长度Q也是说从当前地址向后昄几个地址的内宏V?<br>f 表示昄的格式,参见上面。如果地址所指的是字W串Q那么格式可以是sQ如果地十是<br>指o地址Q那么格式可以是i?</p> <p>u 表示从当前地址往后请求的字节敎ͼ如果不指定的话,GDB默认?个bytes。u参数?br>以用下面的字W来代替Qb表示单字节,h表示双字节,w表示四字节,g表示八字节。当<br>我们指定了字节长度后QGDB会从指内存定的内存地址开始,d指定字节Qƈ把其当作<br>一个值取出来?<br>表示一个内存地址?<br>n/f/u三个参数可以一起用。例如: <br>命oQx/3uh 0x54320 表示Q从内存地址0x54320d内容Qh表示以双字节Z个单位,3<br>表示三个单位Qu表示按十六进制显C?<br>六、自动显C?<br>你可以设|一些自动显C的变量Q当E序停住Ӟ或是在你单步跟踪Ӟq些变量会自动显<br>C。相关的GDB命o是display?<br>display <br>display/ <br>display/ <br>expr是一个表辑ּQfmt表示昄的格式,addr表示内存地址Q当你用display讑֮好了一<br>个或多个表达式后Q只要你的程序被停下来,GDB会自动显CZ所讄的这些表辑ּ的倹{?<br>格式i和s同样被display支持Q一个非常有用的命o是: <br>display/i $pc <br>$pc是GDB的环境变量,表示着指o的地址Q?i则表C出格式ؓ机器指o码,也就是汇<br>~。于是当E序停下后,׃出现源代码和机器指o码相对应的情形,q是一个很有意思的<br>功能?<br>下面是一些和display相关的GDB命oQ?<br>undisplay <br>delete display <br>删除自动昄Qdnums意ؓ所讄好了的自动显式的~号。如果要同时删除几个Q编号可?br>用空格分隔,如果要删除一个范围内的编P可以用减可C(如:2-5Q?<br>disable display <br>enable display <br>disable和enalbe不删除自动显C的讄Q而只是让其失效和恢复?</p> <p>info display <br>查看display讄的自动显C的信息。GDB会打Z张表|向你报告当然调试中设|了?br>个自动昄讄Q其中包括,讄的编P表达式,是否enable?<br>七、设|显C选项 <br>GDB中关于显C的选项比较多,q里我只例D大多数常用的选项?<br>set print address <br>set print address on <br>打开地址输出Q当E序昄函数信息ӞGDB会显出函数的参数地址。系l默认ؓ打开的,<br>如: <br>(gdb) f <br>#0 set_quotes (lq=0x34c78 "<<", rq=0x34c88 ">>") <br>at input.c:530 <br>530 if (lquote != def_lquote) <br>set print address off <br>关闭函数的参数地址昄Q如Q?<br>(gdb) set print addr off <br>(gdb) f <br>#0 set_quotes (lq="<<", rq=">>") at input.c:530 <br>530 if (lquote != def_lquote) <br>show print address <br>查看当前地址昄选项是否打开?<br>set print array <br>set print array on <br>打开数组昄Q打开后当数组昄Ӟ每个元素占一行,如果不打开的话Q每个元素则以?br>号分隔。这个选项默认是关闭的。与之相关的两个命o如下Q我׃再多说了?<br>set print array off <br>show print array <br>set print elements <br>q个选项主要是设|数l的Q如果你的数l太大了Q那么就可以指定一个来指定数据昄?br>最大长度,当到达这个长度时QGDB׃再往下显CZ。如果设|ؓ0Q则表示不限制?<br>show print elements </p> <p>查看print elements的选项信息?<br>set print null-stop <br>如果打开了这个选项Q那么当昄字符串时Q遇到结束符则停止显C。这个选项默认为off?<br>set print pretty on <br>如果打开printf prettyq个选项Q那么当GDB昄l构体时会比较漂亮。如Q?<br>$1 = { <br>next = 0x0, <br>flags = { <br>sweet = 1, <br>sour = 1 <br>}, <br>meat = 0x54 "Pork" <br>} <br>set print pretty off <br>关闭printf prettyq个选项QGDB昄l构体时会如下显C: <br>$1 = {next = 0x0, flags = {sweet = 1, sour = 1}, meat = 0x54 "Pork"} <br>show print pretty <br>查看GDB是如何显C结构体的?<br>set print sevenbit-strings <br>讄字符昄Q是否按“\nnn”的格式显C,如果打开Q则字符串或字符数据按\nnn昄Q?br>?#8220;\065”?<br>show print sevenbit-strings <br>查看字符昄开x否打开?<br>set print union <br>讄昄l构体时Q是否显式其内的联合体数据。例如有以下数据l构Q?<br>typedef enum {Tree, Bug} Species; <br>typedef enum {Big_tree, Acorn, Seedling} Tree_forms; <br>typedef enum {Caterpillar, Cocoon, Butterfly} <br>Bug_forms; <br>struct thing { <br>Species it; <br>union { </p> <p>Tree_forms tree; <br>Bug_forms bug; <br>} form; <br>}; <br>struct thing foo = {Tree, {Acorn}}; <br>当打开q个开xQ执?p foo 命o后,会如下显C: <br>$1 = {it = Tree, form = {tree = Acorn, bug = Cocoon}} <br>当关闭这个开xQ执?p foo 命o后,会如下显C: <br>$1 = {it = Tree, form = {...}} <br>show print union <br>查看联合体数据的昄方式 <br>set print object <br>在C++中,如果一个对象指针指向其zc,如果打开q个选项QGDB会自动按照虚Ҏ<br>调用的规则显C出,如果关闭q个选项的话QGDB׃虚函数表了。这个选项默认?br>off?<br>show print object <br>查看对象选项的设|?<br>set print static-members <br>q个选项表示Q当昄一个C++对象中的内容是,是否昄其中的静态数据成员。默认是<br>on?<br>show print static-members <br>查看静态数据成员选项讄?<br>set print vtbl <br>当此选项打开ӞGDB用比较规整的格式来昄虚函数表时。其默认是关闭的?<br>show print vtbl <br>查看虚函数显C格式的选项?<br>八、历史记?<br>当你用GDB的print查看E序q行时的数据Ӟ你每一个print都会被GDB记录下来。GDB<br>会以$1, $2, $3 .....q样的方式ؓ你每一个print命o~上受于是,你可以用这个编可?br>以前的表辑ּQ如$1。这个功能所带来的好处是Q如果你先前输入了一个比较长的表辑ּQ?br>如果你还x看这个表辑ּ的|你可以用历史记录来讉KQ省M重复输入?</p> <p>九、GDB环境变量 <br>你可以在GDB的调试环境中定义自己的变量,用来保存一些调试程序中的运行数据。要?br>义一个GDB的变量很单只需。用GDB的set命o。GDB的环境变量和UNIX一P<br>也是?起头。如Q?<br>set $foo = *object_ptr <br>使用环境变量ӞGDB会在你第一ơ用时创徏q个变量Q而在以后的用中Q则直接?br>其c倹{环境变量没有类型,你可以给环境变量定义M的类型。包括结构体和数l?<br>show convenience <br>该命令查看当前所讄的所有的环境变量?<br>q是一个比较强大的功能Q环境变量和E序变量的交互用,得程序调试更为灵zM捗?br>例如Q?<br>set $i = 0 <br>print bar[$i++]->contents <br>于是Q当你就不必Qprint bar[0]->contents, print bar[1]->contents地输入命令了。输入这L<br>命o后,只用敲回车,重复执行上一条语句,环境变量会自动篏加,从而完成逐个输出的功<br>能?<br>十、查看寄存器 <br>要查看寄存器的|很简单,可以使用如下命oQ?<br>info registers <br>查看寄存器的情况。(除了点寄存器) <br>info all-registers <br>查看所有寄存器的情c(包括点寄存器) <br>info registers <br>查看所指定的寄存器的情c?<br>寄存器中攄了程序运行时的数据,比如E序当前q行的指令地址QipQ,E序的当前堆?br>地址QspQ等{。你同样可以使用print命o来访问寄存器的情况,只需要在寄存器名字前<br>加一?W号可以了。如Qp $eip?</p> <p>改变E序的执?<br>——————?<br>一旦用GDB挂上被调试程序,当程序运行v来后Q你可以Ҏ自己的调试思\来动态地<br>在GDB中更改当前被调试E序的运行线路或是其变量的|q个强大的功能能够让你更?br>的调试你的程序,比如Q你可以在程序的一ơ运行中走遍E序的所有分支?<br>一、修改变量?<br>修改被调试程序运行时的变量|在GDB中很Ҏ实现Q用GDB的print命o卛_完成?br>如: <br>(gdb) print x=4 <br>x=4q个表达式是C/C++的语法,意ؓ把变量x的g改ؓ4Q如果你当前调试的语a?br>PascalQ那么你可以使用Pascal的语法:x:=4?<br>在某些时候,很有可能你的变量和GDB中的参数冲突Q如Q?<br>(gdb) whatis width <br>type = double <br>(gdb) p width <br>$4 = 13 <br>(gdb) set width=47 <br>Invalid syntax in expression. <br>因ؓQset width是GDB的命令,所以,出现?#8220;Invalid syntax in expression”的设|错误,<br>此时Q你可以使用set var命o来告诉GDBQwidth不是你GDB的参敎ͼ而是E序的变量名Q?br>如: <br>(gdb) set var width=47 <br>另外Q还可能有些情况QGDBq不报告q种错误Q所以保险v见,在你改变E序变量取?br>Ӟ最好都使用set var格式的GDB命o?<br>二、蟩转执?<br>一般来_被调试程序会按照E序代码的运行顺序依ơ执行。GDB提供了ؕ序执行的功能Q?br>也就是说QGDB可以修改E序的执行顺序,可以让程序执行随意蟩跃。这个功能可以由GDB<br>的jump命o来完Q?<br>jump </p> <p>指定下一条语句的q行炏V可以是文g的行P可以是file:line格式Q可以是+numq种?br>U量格式。表式着下一条运行语句从哪里开始?<br>jump <br>q里?<br>是代码行的内存地址?<br>注意Qjump命o不会改变当前的程序栈中的内容Q所以,当你从一个函数蟩到另一个函?br>Ӟ当函数运行完q回时进行弹栈操作时必然会发生错误,可能l果q是非常奇怪的Q甚?br>于生程序Core Dump。所以最好是同一个函Cq行跌{?<br>熟悉汇编的h都知道,E序q行Ӟ有一个寄存器用于保存当前代码所在的内存地址。所以,<br>jump命o也就是改变了q个寄存器中的倹{于是,你可以?#8220;set $pc”来更改蟩转执?br>的地址。如Q?<br>set $pc = 0x485 <br>三、生信号量 <br>使用singal命oQ可以生一个信号量l被调试的程序。如Q中断信号Ctrl+C。这非常方便<br>于程序的调试Q可以在E序q行的Q意位|设|断点,q在该断点用GDB产生一个信号量Q?br>q种_地在某处产生信号非常有利E序的调试?<br>语法是:signal QUNIX的系l信号量通常??5。所以取g在这个范围?<br>single命o和shell的kill命o不同Q系l的kill命o发信L被调试程序时Q是由GDB?br>LQ而single命o所发出一信号则是直接发给被调试程序的?<br>四、强制函数返?<br>如果你的调试断点在某个函CQƈq有语句没有执行完。你可以使用return命o强制函数<br>忽略q没有执行的语句q返回?<br>return <br>return <br>使用return命o取消当前函数的执行,q立卌回,如果指定了,那么该表辑ּ的g被认<br>作函数的q回倹{?<br>五、强制调用函?</p> <p>call <br>表达式中可以一是函敎ͼ以此辑ֈ强制调用函数的目的。ƈ昄函数的返回|如果函数q?br>回值是voidQ那么就不显C?<br>另一个相似的命o也可以完成这一功能——printQprint后面可以跟表辑ּQ所以也可以用他<br>来调用函敎ͼprint和call的不同是Q如果函数返回voidQcall则不昄Qprint则显C函数返<br>回|q把该值存入历史数据中?<br>在不同语a中用GDB <br>—————————?<br>GDB支持下列语言QC, C++, Fortran, PASCAL, Java, Chill, assembly, ?Modula-2。一般说<br>来,GDB会根据你所调试的程序来定当然的调试语aQ比如:发现文g名后~?#8220;.c”<br>的,GDB会认为是CE序。文件名后缀?#8220;.C, .cc, .cp, .cpp, .cxx, .c++”的,GDB会认为是<br>C++E序。而后~?#8220;.f, .F”的,GDB会认为是FortranE序Q还有,后缀为如果是“.s, .S”<br>的会认ؓ是汇~语a?<br>也就是说QGDB会根据你所调试的程序的语言Q来讄自己的语a环境Qƈ让GDB的命?br>跟着语言环境的改变而改变。比如一些GDB命o需要用到表辑ּ或变量时Q这些表辑ּ?br>变量的语法,完全是根据当前的语言环境而改变的。例如C/C++中对指针的语法是*pQ而在<br>Modula-2中则是p^。ƈ且,如果你当前的E序是由几种不同语言一同编译成的,那到在调<br>试过E中QGDB也能Ҏ不同的语a自动地切换语a环境。这U跟着语言环境而改变的?br>能,真是体脓开发h员的一U设计?<br>下面是几个相关于GDB语言环境的命令: <br>show language <br>查看当前的语a环境。如果GDB不能识ؓ你所调试的编E语aQ那么,C语言被认为是?br>认的环境?<br>info frame <br>查看当前函数的程序语a?<br>info source <br>查看当前文g的程序语a?<br>如果GDB没有出当前的程序语aQ那么你也可以手动设|当前的E序语言。用set <br>language命o卛_做到?<br>当set language命o后什么也不跟的话Q你可以查看GDB所支持的语aU类Q?</p> <p>(gdb) set language <br>The currently understood settings are: <br>local or auto Automatic setting based on source file <br>c Use the C language <br>c++ Use the C++ language <br>asm Use the Asm language <br>chill Use the Chill language <br>fortran Use the Fortran language <br>java Use the Java language <br>modula-2 Use the Modula-2 language <br>pascal Use the Pascal language <br>scheme Use the Scheme language <br>于是你可以在set language后跟上被列出来的E序语言名,来设|当前的语言环境?<br>后记 <br>—?<br>GDB是一个强大的命o行调试工兗大家知道命令行的强大就是在于,其可以Ş成执行序<br>列,形成脚本。UNIX下的软g全是命o行的Q这l程序开发提代供了极大的便利Q命令行<br>软g的优势在于,它们可以非常Ҏ的集成在一P使用几个单的已有工具的命令,可<br>以做Z个非常强大的功能?<br>于是UNIX下的软g比Windows下的软g更能有机地结合,各自发挥各自的长处,l合?br>更ؓ强劲的功能。而Windows下的囑Ş软g基本上是各自Q互怸能调用,很不利于<br>各种软g的相互集成。在q里q不是要和Windows做个什么比较,所?#8220;寸有所长,有<br>所?#8221;Q图形化工具q是有不如命令行的地斏V(看到q句话时Q希望各位千万再也不要认?br>我就?#8220;鄙视囑Ş界面”Q和我抬杠了 Q?<br>我是Ҏ版本?.1.1的GDB所写的q篇文章Q所以可能有些功能已被修改,或是又有?br>为强劲的功能。而且Q我写得非常仓促Q写得比较简略,q且Q其中我已经看到有许多错?br>字了Q我用五W,所以错字让你看不懂Q,所以,我在q里Ҏ文中的差错表CZ分的歉意?<br>文中所|列的GDB的功能时Q我只是|列了一些带用的GDB的命令和使用ҎQ其实,<br>我这里只讲述的功能大U只占GDB所有功能的60%吧,详细的文档,q是h看GDB?br>帮助和用手册吧Q或许,q段旉Q如果我有空Q我再写一GDB的高U用?<br>我个人非常喜ƢGDB的自动调试的功能Q这个功能真的很强大Q试惻I我在UNIX下写?br>脚本Q让脚本自动~译我的E序Q被自动调试Qƈ把结果报告出来,调试成功Q自动checkin<br>源码库。一个命令,~译带着调试带着checkinQ多爽啊。只是GDB对自动化调试目前支持<br>q不是很成熟Q只能实现半自动化,真心期望着GDB的自动化调试功能的成熟?</p> <p>如果各位对GDB或是别的技术问题有兴趣的话Q欢q和我讨Z。本人目前主要在UNIX<br>下做产品软g的开发,所以,对UNIX下的软g开发比较熟悉,当然Q不单单是技术,对Y<br>件工E实施,软g设计Q系l分析,目理我也略有心得。欢q大家找我交,QQQ是:<br>753640QMSN是:<a href="mailto:haoel@hotmail.com"><font color=#336699>haoel@hotmail.com</font></a>Q?<br>RelatedEntriesQ?<br>文g操作 - 10 28, 2003 <br>OSW:12.CVS讄与应?- 10 28, 2003 <br>MySQL AB Acquires Alzato - 10 24, 2003 <br>cvs - 10 24, 2003 <br>使用CVSq行版本理 - 10 23, 2003</p> <img src ="http://www.shnenglu.com/true/aggbug/71749.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/true/" target="_blank">true</a> 2009-01-11 20:21 <a href="http://www.shnenglu.com/true/archive/2009/01/11/71749.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>std::queue的front的问?/title><link>http://www.shnenglu.com/true/archive/2008/06/10/52731.html</link><dc:creator>true</dc:creator><author>true</author><pubDate>Tue, 10 Jun 2008 03:39:00 GMT</pubDate><guid>http://www.shnenglu.com/true/archive/2008/06/10/52731.html</guid><wfw:comment>http://www.shnenglu.com/true/comments/52731.html</wfw:comment><comments>http://www.shnenglu.com/true/archive/2008/06/10/52731.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.shnenglu.com/true/comments/commentRss/52731.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/true/services/trackbacks/52731.html</trackback:ping><description><![CDATA[<p> </p> msdn上的解析Q?br> <pre><strong>value_type& front( );</strong>  <strong>const value_type& front( ) const;</strong></pre> <p>Returns a reference to the first element at the front of the queue.<br><br>L下面CZ代码<br>queue<int> intqueue;<br>intqueue.push(1);<br>intqueue.push(2);<br>int head = intqueue.front();//int&可以隐式转换为int?<br>intqueue.pop();//对头元素弹出队?br>cout << head << endl;//输出1Qfront应该q回的是"引用",但pop之后Qؓ什么head的输有效(引用q有效?)Q?br><br></p> <img src ="http://www.shnenglu.com/true/aggbug/52731.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/true/" target="_blank">true</a> 2008-06-10 11:39 <a href="http://www.shnenglu.com/true/archive/2008/06/10/52731.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>epoll()实现分析【ZT?/title><link>http://www.shnenglu.com/true/archive/2008/06/01/51848.html</link><dc:creator>true</dc:creator><author>true</author><pubDate>Sun, 01 Jun 2008 14:55:00 GMT</pubDate><guid>http://www.shnenglu.com/true/archive/2008/06/01/51848.html</guid><wfw:comment>http://www.shnenglu.com/true/comments/51848.html</wfw:comment><comments>http://www.shnenglu.com/true/archive/2008/06/01/51848.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/true/comments/commentRss/51848.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/true/services/trackbacks/51848.html</trackback:ping><description><![CDATA[<div id="plj55z5" class=tit>epoll()实现分析<br><br><a >http://hi.baidu.com/rwen2012/blog/item/0f2f8c13eb7f3621dd5401a8.html</a></div> <div id="5j5r5fz" class=date>2007-07-04 17:50</div> <table style="TABLE-LAYOUT: fixed"> <tbody> <tr> <td> <div id="1dl5vjt" class=cnt id=blog_text>                                            <br>/*<br>* This structure is stored inside the "private_data" member of the file<br>* structure and rapresent the main data sructure for the eventpoll<br>* interface.<br>*/<br>struct eventpoll {<br>   /* Protect the this structure access */<br>   rwlock_t lock;<br></div> </td> </tr> </tbody> </table> <img src ="http://www.shnenglu.com/true/aggbug/51848.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/true/" target="_blank">true</a> 2008-06-01 22:55 <a href="http://www.shnenglu.com/true/archive/2008/06/01/51848.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>在Linux上开发网l服务器的一些相关细?poll与epoll[转]http://www.shnenglu.com/true/archive/2008/06/01/51843.htmltruetrueSun, 01 Jun 2008 14:15:00 GMThttp://www.shnenglu.com/true/archive/2008/06/01/51843.htmlhttp://www.shnenglu.com/true/comments/51843.htmlhttp://www.shnenglu.com/true/archive/2008/06/01/51843.html#Feedback0http://www.shnenglu.com/true/comments/commentRss/51843.htmlhttp://www.shnenglu.com/true/services/trackbacks/51843.htmlhttp://hi.baidu.com/xproduct/blog/calendar/200706
2007-06-30 23:58
随着2.6内核对epoll的完全支持,|络上很多的文章和示例代码都提供了这样一个信息:使用epoll代替传统的poll能给|络服务应用带来性能?的提升。但大多文章里关于性能提升的原因解释的较少Q这里我试分析一下内核(2.6.21.1Q代码中poll与epoll的工作原理,然后再通过一?试数据来对比具体效果?br>
   POLLQ?br>
   先说pollQpoll或select为大部分Unix/LinuxE序员所熟悉Q这俩个东西原理cMQ性能上也不存在明昑ַ异,但selectҎ监控的文件描q符数量有限Ӟ所以这里选用poll做说明?br>
   poll是一个系l调用,其内核入口函Cؓsys_pollQsys_poll几乎不做M处理直接调用do_sys_pollQdo_sys_poll的执行过E可以分Z个部分:

   1Q将用户传入的pollfd数组拯到内核空_因ؓ拯操作和数l长度相养I旉上这是一个OQnQ操作,q一步的代码在do_sys_poll中包括从函数开始到调用do_poll前的部分?br>
   2Q查询每个文件描q符对应讑֤的状态,如果该设备尚未就l,则在该设备的{待队列中加入一ƈl箋查询下一讑֤的状态。查询完所有设备后如果没有一个设 备就l,q时则需要挂起当前进E等待,直到讑֤qA或者超Ӟ挂v操作是通过调用schedule_timeout执行的。设备就l后q程被通知l箋q?行,q时再次遍历所有设备,以查扑ְl设备。这一步因Zơ遍历所有设备,旉复杂度也是OQnQ,q里面不包括{待旉。相关代码在do_poll函数 中?br>
   3Q将获得的数据传送到用户I间q执行释攑ֆ存和剥离{待队列{善后工作,向用L间拷贝数据与剥离{待队列{操作的的时间复杂度同样是OQnQ,具体代码包括do_sys_poll函数中调用do_poll后到l束的部分?br>
   EPOLLQ?br>
   接下来分析epollQ与poll/select不同Qepoll不再是一个单独的pȝ调用Q而是由epoll_create/epoll_ctl/epoll_wait三个pȝ调用l成Q后面将会看到这样做的好处?br>
   先来看sys_epoll_create(epoll_create对应的内核函敎ͼQ这个函C要是做一些准备工作,比如创徏数据l构Q初始化数据q最l返回一个文件描q符Q表C新创徏的虚拟epoll文gQ,q个操作可以认ؓ是一个固定时间的操作?br>
       epoll是做Z个虚拟文件系l来实现的,q样做至有以下两个好处Q?br>
       1Q可以在内核里维护一些信息,q些信息在多ơepoll_wait间是保持的,比如所有受监控的文件描q符?br>
       2Q?epoll本n也可以被poll/epoll;

   具体epoll的虚拟文件系l的实现和性能分析无关Q不再赘q?br>
   在sys_epoll_create中还能看C个细节,是epoll_create的参数size在现阶段是没有意义的Q只要大于零p?br>
   接着是sys_epoll_ctl(epoll_ctl对应的内核函敎ͼQ需要明的是每ơ调用sys_epoll_ctl只处理一个文件描q符Q这里主 要描q当op为EPOLL_CTL_ADD时的执行q程Qsys_epoll_ctl做一些安全性检查后q入ep_insertQep_insert里将 ep_poll_callback做ؓ回掉函数加入讑֤的等待队列(假定q时讑֤未qAQ,׃每次poll_ctl只操作一个文件描q符Q因此也可以 认ؓq是一个O(1)操作

       ep_poll_callback函数很关键,它在所{待的设备就l后被系l回掉,执行两个操作Q?br>
   1Q将qA讑֤加入qA队列Q这一步避免了像poll那样在设备就l后再次轮询所有设备找qA者,降低了时间复杂度Q由OQnQ到OQ?Q?

   2Q唤醒虚拟的epoll文g;

   最后是sys_epoll_waitQ这里实际执行操作的是ep_poll函数。该函数{待进E自w插入虚拟epoll文g的等待队列,直到被唤醒(?上面ep_poll_callback函数描述Q,最后执行ep_events_transfer结果拷贝到用户I间。由于只拯qA讑֤信息Q所以这 里的拯是一个O(1Q操作?br>
   q有一个让人关心的问题是epoll对EPOLLET的处理,卌沿触发的处理Q粗略看代码是把一部分水^触发模式下内核做的工作交l用h处理Q直觉上不会Ҏ能有太大媄响,感兴的朋友Ƣ迎讨论?br>
   POLL/EPOLLҎQ?br>
   表面上poll的过E可以看作是׃ơepoll_create/若干ơepoll_ctl/一ơepoll_wait/一ơclose{系l调用构成, 实际上epollpoll分成若干部分实现的原因正是因为服务器软g中用poll的特点(比如Web服务器)Q?br>
   1Q需要同时poll大量文g描述W?

   2Q每ơpoll完成后就l的文g描述W只占所有被poll的描q符的很一部分?br>
   3Q前后多ơpoll调用Ҏ件描q符数组QufdsQ的修改只是很小;

   传统的poll函数相当于每ơ调用都重v炉灶Q从用户I间完整dufdsQ完成后再次完全拯到用L_另外每次poll都需要对所有设备做臛_做一ơ加入和删除{待队列操作Q这些都是低效的原因?br>
       epoll以上情况都l化考虑Q不需要每ơ都完整d输出ufdsQ只需使用epoll_ctl调整其中一部分,不需要每?epoll_wait都执行一ơ加入删除等待队列操作,另外改进后的机制使的不必在某个设备就l后搜烦整个讑֤数组q行查找Q这些都能提高效率。另外最?昄一点,从用L使用来说Q用epoll不必每次都轮询所有返回结果已扑և其中的就l部分,OQnQ变OQ?Q,Ҏ能也提高不?br>
   此外q里q发C点,是不是将epoll_ctlҎ一ơ可以处理多个fdQ像semctl那样Q会提高些许性能呢?特别是在假设pȝ调用比较耗时的基上。不q关于系l调用的耗时问题q会在以后分析?br>
   POLL/EPOLL试数据ҎQ?br>
   试的环境:我写了三D代码来分别模拟服务器,zd的客LQ僵ȝ客户端,服务器运行于一个自~译的标?.6.11内核pȝ上,g?PIII933Q两个客L各自q行在另外的PC上,q两台PC比服务器的硬件性能要好Q主要是保证能轻易让服务器满载,三台机器间用一?00M交换 接?br>
   服务器接受ƈpoll所有连接,如果有request到达则回复一个responseQ然后lpoll?br>
   zd的客LQActive ClientQ模拟若qƈ发的zdq接Q这些连接不间断的发送请求接受回复?br>
   僉|的客LQzombieQ模拟一些只q接但不发送请求的客户端,其目的只是占用服务器的poll描述W资源?br>
       试q程Q保?0个ƈ发活动连接,不断的调整僵q发q接敎ͼ记录在不同比例下使用poll与epoll的性能差别。僵dƈ发连接数Ҏ比例分别是:0Q?0Q?0Q?0Q?0Q?60Q?20Q?40Q?280Q?560Q?120Q?0240?br>
   下图中横轴表C僵dƈ发连接与zdq发q接之比Q纵轴表C完?0000ơ请求回复所p的时_以秒为单位。红色线条表Cpoll数据Q绿色表C?epoll数据。可以看出,poll在所监控的文件描q符数量增加Ӟ其耗时呈线性增长,而epoll则维持了一个^E的状态,几乎不受描述W个数媄响?br>
   在监控的所有客L都是zdӞpoll的效率会略高于epollQ主要在原点附近Q即僉|q发q接?Ӟ图上不易看出来)Q究竟epoll实现比poll复杂Q监控少量描q符q它的?/div>


true 2008-06-01 22:15 发表评论
]]>
CMake-开源跨q_的编译系l?/title><link>http://www.shnenglu.com/true/archive/2008/05/24/50961.html</link><dc:creator>true</dc:creator><author>true</author><pubDate>Sat, 24 May 2008 08:39:00 GMT</pubDate><guid>http://www.shnenglu.com/true/archive/2008/05/24/50961.html</guid><wfw:comment>http://www.shnenglu.com/true/comments/50961.html</wfw:comment><comments>http://www.shnenglu.com/true/archive/2008/05/24/50961.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/true/comments/commentRss/50961.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/true/services/trackbacks/50961.html</trackback:ping><description><![CDATA[<blockquote> <p>官网Q?a title=http://www.cmake.org/HTML/index.html >http://www.cmake.org/HTML/index.html</a></p> <p>本文主要试用CMake~译源代码包中的Demo</p> <p>1.下蝲最新版2.6.0Q我在windows下蝲的是源代码包<a >cmake-2.6.0.zip</a>和预~译好的二进制版?a >cmake-2.6.0-win32-x86.zip</a>.q分别加压到dir目录Q目录随便即可)Q得到dir/cmake-2.6.0,dir/cmake-2.6.0-win32-x86两个文g夏V?/p> <p>2.dir/cmake-2.6.0-win32-x86/bin加到path环境变量中?/p> <p>3.dosH口下进入到dir/cmake-2.6.0下面?/p> <p>4.cd Example</p> <p>5.mkdir build</p> <p>6.cd build</p> <p>7.cmake ..        (两个点表C在上一U目?</p> <p>下面会自动生了sln和vcproj文gQVS2005打开后,可以直接~译q行</p> </blockquote> <img src ="http://www.shnenglu.com/true/aggbug/50961.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/true/" target="_blank">true</a> 2008-05-24 16:39 <a href="http://www.shnenglu.com/true/archive/2008/05/24/50961.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>linux thread在线参?/title><link>http://www.shnenglu.com/true/archive/2008/05/17/50199.html</link><dc:creator>true</dc:creator><author>true</author><pubDate>Sat, 17 May 2008 14:12:00 GMT</pubDate><guid>http://www.shnenglu.com/true/archive/2008/05/17/50199.html</guid><wfw:comment>http://www.shnenglu.com/true/comments/50199.html</wfw:comment><comments>http://www.shnenglu.com/true/archive/2008/05/17/50199.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/true/comments/commentRss/50199.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/true/services/trackbacks/50199.html</trackback:ping><description><![CDATA[<a >http://www.sbin.org/doc/glibc/libc_34.html</a> <img src ="http://www.shnenglu.com/true/aggbug/50199.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/true/" target="_blank">true</a> 2008-05-17 22:12 <a href="http://www.shnenglu.com/true/archive/2008/05/17/50199.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Z么网l传输ascii码不需要进行字节序转换Q?/title><link>http://www.shnenglu.com/true/archive/2008/05/14/49789.html</link><dc:creator>true</dc:creator><author>true</author><pubDate>Wed, 14 May 2008 01:48:00 GMT</pubDate><guid>http://www.shnenglu.com/true/archive/2008/05/14/49789.html</guid><wfw:comment>http://www.shnenglu.com/true/comments/49789.html</wfw:comment><comments>http://www.shnenglu.com/true/archive/2008/05/14/49789.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.shnenglu.com/true/comments/commentRss/49789.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/true/services/trackbacks/49789.html</trackback:ping><description><![CDATA[ascii?byte~码Q所以没有这个问? <img src ="http://www.shnenglu.com/true/aggbug/49789.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/true/" target="_blank">true</a> 2008-05-14 09:48 <a href="http://www.shnenglu.com/true/archive/2008/05/14/49789.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>内存界和泄露调试工具[转]http://www.shnenglu.com/true/archive/2008/03/21/45030.htmltruetrueFri, 21 Mar 2008 02:07:00 GMThttp://www.shnenglu.com/true/archive/2008/03/21/45030.htmlhttp://www.shnenglu.com/true/comments/45030.htmlhttp://www.shnenglu.com/true/archive/2008/03/21/45030.html#Feedback0http://www.shnenglu.com/true/comments/commentRss/45030.htmlhttp://www.shnenglu.com/true/services/trackbacks/45030.html

作者:sixth

用C/C++开发其中最令h头疼的一个问题就是内存管理,有时候ؓ了查找一个内存泄漏或者一个内存访问越界,需要要׃好几天时_如果有一Ƒַ兯够帮助我们做qg事情好了,valgrind正好是q样的一Ƒַ兗?

Valgrind是一Ƒ֟于模拟linux下的E序调试器和剖析器的软g套gQ可以运行于x86, amd64和ppc32架构上。valgrind包含一个核心,它提供一个虚拟的CPUq行E序Q还有一pd的工P它们完成调试Q剖析和一些类似的d。valgrind是高度模块化的,所以开发h员或者用户可以给它添加新的工兯不会损坏己有的l构?

valgrind的官方网址是:http://valgrind.org

你可以在它的|站上下载到最新的valgrindQ它是开放源码和免费的?

一、介l?/strong>

valgrind包含几个标准的工P它们是:

1、memcheck

memcheck探测E序中内存管理存在的问题。它查所有对内存的读/写操作,q截取所有的malloc/new/free/delete调用。因此memcheck工具能够探测C下问题:

1Q用未初始化的内存

2Q读/写已l被释放的内?

3Q读/写内存越?

4Q读/写不恰当的内存栈I间

5Q内存泄?

6Q用malloc/new/new[]和free/delete/delete[]不匹配?

2、cachegrind

cachegrind是一个cache剖析器。它模拟执行CPU中的L1, D1和L2 cacheQ因此它能很_的指Z码中的cache未命中。如果你需要,它可以打印出cache未命中的ơ数Q内存引用和发生cache未命中的每一行代码,每一个函敎ͼ每一个模块和整个E序的摘要。如果你要求更细致的信息Q它可以打印出每一行机器码的未命中ơ数。在x86和amd64上, cachegrind通过CPUID自动探测机器的cache配置Q所以在多数情况下它不再需要更多的配置信息了?

3、helgrind

helgrind查找多线E程序中的竞争数据。helgrind查找内存地址Q那些被多于一条线E访问的内存地址Q但是没有用一致的锁就会被查出。这表示q些地址在多U程间访问的时候没有进行同步,很可能会引v很难查找的时序问题?

二、valgrind对你的程序都做了些什?/strong>

valgrind被设计成非R入式的,它直接工作于可执行文件上Q因此在查前不需要重新编译、连接和修改你的E序。要查一个程序很单,只需要执行下面的命o可以了

valgrind --tool=tool_name program_name

比如我们要对ls -l命o做内存检查,只需要执行下面的命o可以了

valgrind --tool=memcheck ls -l

不管是用哪个工Pvalgrind在开始之前M先取得对你的E序的控制权Q从可执行关联库里读取调试信息。然后在valgrind核心提供的虚拟CPU上运行程序,valgrind会根据选择的工h处理代码Q该工具会向代码中加入检代码,q把q些代码作ؓ最l代码返回给valgrind核心Q最后valgrind核心q行q些代码?

如果要检查内存泄漏,只需要增?-leak-check=yes可以了Q命令如?

valgrind --tool=memcheck --leak-check=yes ls -l

不同工具间加入的代码变化非常的大。在每个作用域的末尾Qmemcheck加入代码查每一片内存的讉K和进行D,代码大小臛_增加12倍,q行速度要比qx?5?0倍?

valgrind模拟E序中的每一条指令执行,因此Q检查工具和剖析工具不仅仅是对你的应用程序,q有对共享库QGNU C库,X的客L库都起作用?

三、现在开?/strong>

首先Q在~译E序的时候打开调试模式Qgcc~译器的-g选项Q。如果没有调试信息,即最好的valgrind工具也将中能够猜特定的代码是属于哪一个函数。打开调试选项q行~译后再用valgrind查,valgrind会l你的个详细的报告,比如哪一行代码出C内存泄漏?

当检查的是C++E序的时候,q应该考虑另一个选项 -fno-inline。它使得函数调用铑־清晰Q这样可以减你在浏览大型C++E序时的混ؕ。比如在使用q个选项的时候,用memcheck?openoffice很Ҏ。当Ӟ你可能不会做q项工作Q但是用这一选项使得valgrind生成更精的错误报告和减؜乱?

一些编译优化选项(比如-O2或者更高的优化选项)Q可能会使得memcheck提交错误的未初始化报告,因此Qؓ了得valgrind的报告更_Q在~译的时候最好不要用优化选项?

如果E序是通过脚本启动的,可以修改脚本里启动程序的代码Q或者?-trace-children=yes选项来运行脚本?

下面是用memcheck查ls -l命o的输出报告,在终端下执行下面的命?

valgrind --tool=memcheck ls -l

E序会打印出ls -l命o的结果,最后是valgrind的检查报告如下:

==4187==

==4187== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 19 from 2)

==4187== malloc/free: in use at exit: 15,154 bytes in 105 blocks.

==4187== malloc/free: 310 allocs, 205 frees, 60,093 bytes allocated.

==4187== For counts of detected errors, rerun with: -v

==4187== searching for pointers to 105 not-freed blocks.

==4187== checked 145,292 bytes.

==4187==

==4187== LEAK SUMMARY:

==4187== definitely lost: 0 bytes in 0 blocks.

==4187== possibly lost: 0 bytes in 0 blocks.

==4187== still reachable: 15,154 bytes in 105 blocks.

==4187== suppressed: 0 bytes in 0 blocks.

==4187== Reachable blocks (those to which a pointer was found) are not shown.

==4187== To see them, rerun with: --show-reachable=yes

q里?#8220;4187”指的是执行ls -l的进EIDQ这有利于区别不同进E的报告。memcheck会给出报告,分配|和释放了多内存,有多内存泄漏了Q还有多内存的讉K是可辄Q检查了多少字节的内存?

下面举两个用valgrind做内存检查的例子

例子一 (test.c)Q?

#include <string.h>

int main(int argc, char *argv[])
{
char *ptr;

ptr = (char*) malloc(10);
strcpy(ptr, "01234567890");

return 0;
}

~译E序

gcc -g -o test test.c

用valgrind执行命o

valgrind --tool=memcheck --leak-check=yes ./test

报告如下

==4270== Memcheck, a memory error detector.

==4270== Copyright (C) 2002-2006, and GNU GPL'd, by Julian Seward et al.

==4270== Using LibVEX rev 1606, a library for dynamic binary translation.

==4270== Copyright (C) 2004-2006, and GNU GPL'd, by OpenWorks LLP.

==4270== Using valgrind-3.2.0, a dynamic binary instrumentation framework.

==4270== Copyright (C) 2000-2006, and GNU GPL'd, by Julian Seward et al.

==4270== For more details, rerun with: -v

==4270==

==4270== Invalid write of size 1

==4270== at 0x4006190: strcpy (mc_replace_strmem.c:271)

==4270== by 0x80483DB: main (test.c:8)

==4270== Address 0x4023032 is 0 bytes after a block of size 10 alloc'd

==4270== at 0x40044F6: malloc (vg_replace_malloc.c:149)

==4270== by 0x80483C5: main (test.c:7)

==4270==

==4270== Invalid write of size 1

==4270== at 0x400619C: strcpy (mc_replace_strmem.c:271)

==4270== by 0x80483DB: main (test.c:8)

==4270== Address 0x4023033 is 1 bytes after a block of size 10 alloc'd

==4270== at 0x40044F6: malloc (vg_replace_malloc.c:149)

==4270== by 0x80483C5: main (test.c:7)

==4270==

==4270== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 12 from 1)

==4270== malloc/free: in use at exit: 10 bytes in 1 blocks.

==4270== malloc/free: 1 allocs, 0 frees, 10 bytes allocated.

==4270== For counts of detected errors, rerun with: -v

==4270== searching for pointers to 1 not-freed blocks.

==4270== checked 51,496 bytes.

==4270==

==4270==

==4270== 10 bytes in 1 blocks are definitely lost in loss record 1 of 1

==4270== at 0x40044F6: malloc (vg_replace_malloc.c:149)

==4270== by 0x80483C5: main (test.c:7)

==4270==

==4270== LEAK SUMMARY:

==4270== definitely lost: 10 bytes in 1 blocks.

==4270== possibly lost: 0 bytes in 0 blocks.

==4270== still reachable: 0 bytes in 0 blocks.

==4270== suppressed: 0 bytes in 0 blocks.

==4270== Reachable blocks (those to which a pointer was found) are not shown.

==4270== To see them, rerun with: --show-reachable=yes

从这份报告可以看出,q程h4270Qtest.c的第8行写内存界了,引v写内存越界的是strcpy函数Q?

W?行泄漏了10个字节的内存Q引起内存泄漏的是malloc函数?

例子二(test2.c)

#include <stdio.h>

int foo(int x)
{
if (x < 0) {
printf("%d ", x);
}

return 0;
}

int main(int argc, char *argv[])
{
int x;

foo(x);

return 0;
}

~译E序

gcc -g -o test2 test2.c

用valgrind做内存检?

valgrind --tool=memcheck ./test2

输出报告如下

==4285== Memcheck, a memory error detector.

==4285== Copyright (C) 2002-2006, and GNU GPL'd, by Julian Seward et al.

==4285== Using LibVEX rev 1606, a library for dynamic binary translation.

==4285== Copyright (C) 2004-2006, and GNU GPL'd, by OpenWorks LLP.

==4285== Using valgrind-3.2.0, a dynamic binary instrumentation framework.

==4285== Copyright (C) 2000-2006, and GNU GPL'd, by Julian Seward et al.

==4285== For more details, rerun with: -v

==4285==

==4285== Conditional jump or move depends on uninitialised value(s)

==4285== at 0x8048372: foo (test2.c:5)

==4285== by 0x80483B4: main (test2.c:16)

==4285==p p

==4285== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 12 from 1)

==4285== malloc/free: in use at exit: 0 bytes in 0 blocks.

==4285== malloc/free: 0 allocs, 0 frees, 0 bytes allocated.

==4285== For counts of detected errors, rerun with: -v

==4285== All heap blocks were freed -- no leaks are possible.

从这份报告可以看EPID?285Qtest2.c文g的第16行调用了foo函数Q在test2.c文g的第5行foo函数使用了一个未初始化的变量?

valgrindq有很多使用选项Q具体可以查看valgrind的man手册和valgrind官方|站的在U文档?/p>




Windows用户不必沮Q虽然在Windows上没有Valgrind可用Q但是你可以试一试IBM?a >PurifyQ它在功能上和Valgrind怼?br>



true 2008-03-21 10:07 发表评论
]]>
Linux Deamon~程Ҏ[又是转的Q(]http://www.shnenglu.com/true/archive/2007/11/26/37299.htmltruetrueMon, 26 Nov 2007 02:22:00 GMThttp://www.shnenglu.com/true/archive/2007/11/26/37299.htmlhttp://www.shnenglu.com/true/comments/37299.htmlhttp://www.shnenglu.com/true/archive/2007/11/26/37299.html#Feedback1http://www.shnenglu.com/true/comments/commentRss/37299.htmlhttp://www.shnenglu.com/true/services/trackbacks/37299.html  守护q程QDaemonQ是q行在后台的一U特D进E。它独立于控制终端ƈ且周期性地执行某种d或等待处理某些发生的事g。守护进E是一U很有用的进E?Linux的大多数服务器就是用守护q程实现的。比如,Internet服务器inetdQWeb服务器httpd{。同Ӟ守护q程完成许多pȝd。比如,作业规划q程crondQ打印进Elpd{?br>守护q程的编E本wƈ不复杂,复杂的是各种版本的Unix的实现机制不相同,造成不同 Unix环境下守护进E的~程规则q不一致。需要注意,照搬某些书上的规则(特别是BSD4.3和低版本的System VQ到Linux会出现错误的。下面将l出Linux下守护进E的~程要点和详l实例?br>一Q?守护q程及其Ҏ?br>守护q程最重要的特性是后台q行。在q一点上DOS下的帔R内存E序TSR与之怼。其ơ,守护q程必须与其q行前的环境隔离开来。这些环境包括未关闭的文件描q符Q控制终端,会话和进E组Q工作目录以及文件创建掩模等。这些环境通常是守护进E从执行它的父进E(特别是shellQ中l承下来的。最后,守护q程的启动方式有其特D之处。它可以在Linuxpȝ启动时从启动脚本/etc/rc.d中启动,可以׃业规划进Ecrond启动Q还可以qL端(通常?shellQ执行?br>MQ除开q些Ҏ性以外,守护q程与普通进E基本上没有什么区别。因此,~写守护q程实际上是把一个普通进E按照上q的守护q程的特性改造成为守护进E。如果对q程有比较深入的认识更Ҏ理解和编E了?br>二. 守护q程的编E要?br>前面讲过Q不同Unix环境下守护进E的~程规则q不一致。所q的是守护进E的~程原则其实都一P区别在于具体的实现细节不同。这个原则就是要满守护q程的特性。同ӞLinux是基于Syetem V的SVR4q循Posix标准Q实现v来与BSD4相比更方ѝ编E要点如下;
1. 在后台运行?br>为避免挂h制终端将Daemon攑օ后台执行。方法是在进E中调用fork使父q程l止Q让Daemon在子q程中后台执行?br>if(pid=fork())
exit(0);//是父q程Q结束父q程Q子q程l箋
2. q控制l端Q登录会话和q程l?br>有必要先介绍一下Linux中的q程与控制终端,d会话和进E组之间的关p:q程属于一个进E组Q进E组PGIDQ就是进E组长的q程PPIDQ。登录会话可以包含多个进E组。这些进E组׃n一个控制终端。这个控制终端通常是创E的dl端?br>控制l端Q登录会话和q程l通常是从父进E承下来的。我们的目的是要摆脱它们,使之不受它们的媄响。方法是在第1点的基础上,调用setsid()使进E成Z话组长:
setsid();
说明Q当q程是会话组长时setsid()调用p|。但W一点已l保证进E不是会话组ѝsetsid()调用成功后,q程成ؓ新的会话l长和新的进E组长,q与原来的登录会话和q程l脱R由于会话过E对控制l端的独占性,q程同时与控制终端脱R?br>3. 止q程重新打开控制l端
现在Q进E已l成为无l端的会话组ѝ但它可以重新申h开一个控制终端。可以通过使进E不再成Z话组长来止q程重新打开控制l端Q?br>
if(pid=fork())
exit(0);//l束W一子进E,W二子进El(W二子进E不再是会话l长Q?br>4. 关闭打开的文件描q符
q程从创建它的父q程那里l承了打开的文件描q符。如不关闭,会费pȝ资源Q造成q程所在的文gpȝ无法怸以及引v无法预料的错误。按如下Ҏ关闭它们Q?br>for(i=0;i 关闭打开的文件描q符close(i);>
5. 改变当前工作目录
q程zdӞ其工作目录所在的文gpȝ不能怸。一般需要将工作目录改变到根目录。对于需要{储核心,写运行日志的q程工作目录改变到特定目录?tmpchdir("/")
6. 重设文g创徏掩模
q程从创建它的父q程那里l承了文件创建掩模。它可能修改守护q程所创徏的文件的存取位。ؓ防止q一点,文件创建掩模清除:umask(0);
7. 处理SIGCHLD信号
处理SIGCHLD信号q不是必ȝ。但对于某些q程Q特别是服务器进E往往在请求到来时生成子进E处理请求。如果父q程不等待子q程l束Q子q程成为僵进E(zombieQ从而占用系l资源。如果父q程{待子进E结束,增加父q程的负担,影响服务器进E的q发性能。在Linux下可以简单地?SIGCHLD信号的操作设为SIG_IGN?br>signal(SIGCHLD,SIG_IGN);
q样Q内核在子进E结束时不会产生僵尸q程。这一点与BSD4不同QBSD4下必L式等待子q程l束才能释放僵尸q程?br>三. 守护q程实例
守护q程实例包括两部分:ȝ序test.c和初始化E序init.c。主E序每隔一分钟?tmp目录中的日志test.log报告q行状态。初始化E序中的init_daemon函数负责生成守护q程。读者可以利用init_daemon函数生成自己的守护进E?br>1Q?init.c清单

#include < unistd.h >
#include < signal.h >
#include < sys/param.h >
#include < sys/types.h >
#include < sys/stat.h >
void init_daemon(void)
{
int pid;
int i;
if(pid=fork())
exit(0);//是父q程Q结束父q程
else if(pid< 0)
exit(1);//forkp|Q退?br>//是第一子进E,后台l箋执行
setsid();//W一子进E成为新的会话组长和q程l长
//q与控制l端分离
if(pid=fork())
exit(0);//是第一子进E,l束W一子进E?br>else if(pid< 0)
exit(1);//forkp|Q退?br>//是第二子q程Ql?br>//W二子进E不再是会话l长

for(i=0;i< NOFILE;++i)//关闭打开的文件描q符
close(i);
chdir("/tmp");//改变工作目录?tmp
umask(0);//重设文g创徏掩模
return;
}
2Q?test.c清单
#include < stdio.h >
#include < time.h >

void init_daemon(void);//守护q程初始化函?br>
main()
{
FILE *fp;
time_t t;
init_daemon();//初始化ؓDaemon

while(1)//每隔一分钟向test.log报告q行状?br>{
sleep(60);//睡眠一分钟
if((fp=fopen("test.log","a")) >=0)
{
t=time(0);
fprintf(fp,"Im here at %sn",asctime(localtime(&t)) );
fclose(fp);
}
}
}
以上E序在RedHat Linux6.0下编译通过。步骤如下:
~译Qgcc -g -o test init.c test.c
执行Q?/test
查看q程Qps -ef
从输出可以发现test守护q程的各U特性满上面的要求?

true 2007-11-26 10:22 发表评论
]]>
awk用法结【{?/title><link>http://www.shnenglu.com/true/archive/2007/11/13/36495.html</link><dc:creator>true</dc:creator><author>true</author><pubDate>Tue, 13 Nov 2007 04:02:00 GMT</pubDate><guid>http://www.shnenglu.com/true/archive/2007/11/13/36495.html</guid><wfw:comment>http://www.shnenglu.com/true/comments/36495.html</wfw:comment><comments>http://www.shnenglu.com/true/archive/2007/11/13/36495.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/true/comments/commentRss/36495.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/true/services/trackbacks/36495.html</trackback:ping><description><![CDATA[<h2>awk 用法结</h2> <div id="r3bzztp" class=t_msgfont id=postmessage_8063 twffan="done">awk 用法Qawk ' pattern {action} '<br><br>变量?含义<br>ARGC 命o行变元个?br>ARGV 命o行变元数l?br>FILENAME 当前输入文g?br>FNR 当前文g中的记录?br>FS 输入域分隔符Q默认ؓ一个空?br>RS 输入记录分隔W?br>NF 当前记录里域个数<br>NR 到目前ؓ止记录数<br>OFS 输出域分隔符<br>ORS 输出记录分隔W?br><br>1、awk '/101/' file 昄文gfile中包?01的匹配行?br>awk '/101/,/105/' file<br>awk '$1 == 5' file<br>awk '$1 == "CT"' file 注意必须带双引号<br>awk '$1 * $2 >100 ' file<br>awk '$2 >5 && $2<=15' file<br>2、awk '{print NR,NF,$1,$NF,}' file 昄文gfile的当前记录号、域数和每一行的W一个和最后一个域?br>awk '/101/ {print $1,$2 + 10}' file 昄文gfile的匹配行的第一、二个域?0?br>awk '/101/ {print $1$2}' file<br>awk '/101/ {print $1 $2}' file 昄文gfile的匹配行的第一、二个域Q但昄时域中间没有分隔W?br>3、df | awk '$4>1000000 ' 通过道W获得输入,如:昄W?个域满条g的行?br>4、awk -F "|" '{print $1}' file 按照新的分隔W?#8220;|”q行操作?br>awk 'BEGIN { FS="[: \t|]" }<br>{print $1,$2,$3}' file 通过讄输入分隔W(FS="[: \t|]"Q修改输入分隔符?br><br>Sep="|"<br>awk -F $Sep '{print $1}' file 按照环境变量Sep的值做为分隔符?<br>awk -F '[ :\t|]' '{print $1}' file 按照正则表达式的值做为分隔符Q这里代表空根{?、TAB、|同时做ؓ分隔W?br>awk -F '[][]' '{print $1}' file 按照正则表达式的值做为分隔符Q这里代表[、]<br>5、awk -f awkfile file 通过文gawkfile的内容依ơ进行控制?br>cat awkfile<br>/101/{print "\047 Hello! \047"} --遇到匚w行以后打?' Hello! '.\047代表单引受?br>{print $1,$2} --因ؓ没有模式控制Q打印每一行的前两个域?br>6、awk '$1 ~ /101/ {print $1}' file 昄文g中第一个域匚w101的行Q记录)?br>7、awk 'BEGIN { OFS="%"}<br>{print $1,$2}' file 通过讄输出分隔W(OFS="%"Q修改输出格式?br>8、awk 'BEGIN { max=100 ;print "max=" max} BEGIN 表示在处理Q意行之前q行的操作?br>{max=($1 >max ?$1:max); print $1,"Now max is "max}' file 取得文gW一个域的最大倹{?br>Q表辑ּ1?表达?:表达? 相当于:<br>if (表达?)<br>表达?<br>else<br>表达?<br>awk '{print ($1>4 ? "high "$1: "low "$1)}' file<br>9、awk '$1 * $2 >100 {print $1}' file 昄文g中第一个域匚w101的行Q记录)?br>10、awk '{$1 == 'Chi' {$3 = 'China'; print}' file 扑ֈ匚w行后先将W?个域替换后再昄该行Q记录)?br>awk '{$7 %= 3; print $7}' file 第7域被3除,q将余数赋给W?域再打印?br>11、awk '/tom/ {wage=$2+$3; printf wage}' file 扑ֈ匚w行后为变量wage赋值ƈ打印该变量?br>12、awk '/tom/ {count++;}<br>END {print "tom was found "count" times"}' file END表示在所有输入行处理完后q行处理?br>13、awk 'gsub(/\$/,"");gsub(/,/,""); cost+=$4;<br>END {print "The total is $" cost>"filename"}' file gsub函数用空串替??再将l果输出到filename中?br>1 2 3 $1,200.00<br>1 2 3 $2,300.00<br>1 2 3 $4,000.00<br><br>awk '{gsub(/\$/,"");gsub(/,/,"");<br>if ($4>1000&&$4<2000) c1+=$4;<br>else if ($4>2000&&$4<3000) c2+=$4;<br>else if ($4>3000&&$4<4000) c3+=$4;<br>else c4+=$4; }<br>END {printf "c1=[%d];c2=[%d];c3=[%d];c4=[%d]\n",c1,c2,c3,c4}"' file<br>通过if和else if完成条g语句<br><br>awk '{gsub(/\$/,"");gsub(/,/,"");<br>if ($4>3000&&$4<4000) exit;<br>else c4+=$4; }<br>END {printf "c1=[%d];c2=[%d];c3=[%d];c4=[%d]\n",c1,c2,c3,c4}"' file<br>通过exit在某条g旉出,但是仍执行END操作?br>awk '{gsub(/\$/,"");gsub(/,/,"");<br>if ($4>3000) next;<br>else c4+=$4; }<br>END {printf "c4=[%d]\n",c4}"' file<br>通过next在某条g时蟩q该行,对下一行执行操作?br><br><br>14、awk '{ print FILENAME,$0 }' file1 file2 file3>fileall 把file1、file2、file3的文件内容全部写到fileall中,格式?br>打印文gq前|文件名?br>15、awk ' $1!=previous { close(previous); previous=$1 } <br>{print substr($0,index($0," ") +1)>$1}' fileall 把合q后的文仉新分拆ؓ3个文件。ƈ与原文g一致?br>16、awk 'BEGIN {"date"|getline d; print d}' 通过道把date的执行结果送给getlineQƈ赋给变量dQ然后打印?br>17、awk 'BEGIN {system("echo \"Input your name:\\c\""); getline d;print "\nYour name is",d,"\b!\n"}'<br>通过getline命o交互输入nameQƈ昄出来?br>awk 'BEGIN {FS=":"; while(getline< "/etc/passwd" >0) { if($1~"050[0-9]_") print $1}}'<br>打印/etc/passwd文g中用户名包含050x_的用户名?br><br>18、awk '{ i=1;while(i<NF) {print NF,$i;i++}}' file 通过while语句实现循环?br>awk '{ for(i=1;i<NF;i++) {print NF,$i}}' file 通过for语句实现循环?<br>type file|awk -F "/" '<br>{ for(i=1;i<NF;i++)<br>{ if(i==NF-1) { printf "%s",$i }<br>else { printf "%s/",$i } }}' 昄一个文件的全\径?br>用for和if昄日期<br>awk 'BEGIN {<br>for(j=1;j<=12;j++)<br>{ flag=0;<br>printf "\n%d月䆾\n",j;<br>for(i=1;i<=31;i++)<br>{<br>if (j==2&&i>28) flag=1;<br>if ((j==4||j==6||j==9||j==11)&&i>30) flag=1;<br>if (flag==0) {printf "%02d%02d ",j,i}<br>}<br>}<br>}'<br>19、在awk中调用系l变量必ȝ单引P如果是双引号Q则表示字符?br>Flag=abcd<br>awk '{print '$Flag'}' l果为abcd<br>awk '{print "$Flag"}' l果?Flag</div> <img src ="http://www.shnenglu.com/true/aggbug/36495.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/true/" target="_blank">true</a> 2007-11-13 12:02 <a href="http://www.shnenglu.com/true/archive/2007/11/13/36495.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>|络q接E序SSH为Linux助力[转]http://www.shnenglu.com/true/archive/2007/07/30/28998.htmltruetrueMon, 30 Jul 2007 03:03:00 GMThttp://www.shnenglu.com/true/archive/2007/07/30/28998.htmlhttp://www.shnenglu.com/true/comments/28998.htmlhttp://www.shnenglu.com/true/archive/2007/07/30/28998.html#Feedback0http://www.shnenglu.com/true/comments/commentRss/28998.htmlhttp://www.shnenglu.com/true/services/trackbacks/28998.html  Z么要使用SSH
  上面所说的各项功能,早期BSD所提供的r指o(rsh, rlogin, rcp)几乎都能完成,那ؓ什么要用SSH?理由在于r指o所提供的连接ƈ没有l过~码加密,有心人只要用合适的工具p够截下你所输入的每一个字,包括密码。如果你利用X protocol在远端机器执行XE序Q也可以截下你传输的资料,当然也包括密码。而SSH针对了q些q做了弥补,Ҏ传输的资料加以编码?
  SSH2与SSH1
  SSH2对SSH1的程序码做了大幅度的改写,ҎSSH公司的说? SSH2?8%的程序码和SSH1的不一栗除了SSH1所提供的RSA法之外,SSH2也提供了另外的公开金匙~码法以及金匙交换法,SSH2预设采用DSA~码以及Diffie-Hellman金匙交换法。此?更提供了SFTP,使我们能在FTP斚w也得到安全的保障?
  文g下蝲Q?a href="ftp://ftp.ssh.com/pub/SSH/">ftp://ftp.SSH.com/pub/SSH/Qlinuxnews.idv.tw/download/SSH-1.2.31.tar.gz 1MB for Linux ServerQlinuxnews.idv.tw/download/SSHWin-2.4.0-pl2.exe 5MB for Win32 Client
  安装环境QRedhat 7.0
  1、下载完后将文g解压~?
  tar zxvf SSH-1.2.31.tar.gz
  2、开始编译,安装
  cd SSH-1.2.31;
  ./configure;
  make;
  make install;
  3、编?etc/rc.d/rc.local加入/usr/sbin/SSHd以便开动启动?
  4、完?
  如果你是2台Linux要相q就都要装这个程序,如果是Windowspȝ要连Linux的话p安装for Winxx的程序。Winxx部分误p试?
  Linux的用方?
  /usr/bin/SSH -l username 187.136.5.1
  然后输入密码Q连q去后是一般的文字界面Q就可以开始用了?
  另外QSSH可以直接使用rootd?
  注:如果你要对连接进来的IP做限制的话可以编?etc/hosts.deny?etc/hosts.allow
  CZ如下Q?
  /etc/hosts.denyQ?
  ALL:ALL
  #止所有IP使用所有的服务
  /etc/hosts.allowQ?
  SSHd:111.222.333.444
  #开?11.222.333.444使用SSHq接
  利用SSH来ftp
  1、Linux对Linux传文Ӟ
  上传Qscp wrong.php bha@187.136.5.1:
  q时会问你密码,输入密码吧?
  说明Q?
  scp是指?
  wrong.php是本地端的文件名
  bha@187.136.5.1是远端的用户(user name)和IP
  最后记住那个冒号一定要加,那是q端的home directory?
 下传Qscp bha@187.136.5.1:wrong.php .
  说明Q?
  用scp?a href="mailto:bha@187.136.5.1">bha@187.136.5.1目录的wrong.php拯到目前的目录(是那个.)
  2、Win对Linux传文Ӟ
  lsQ就是dir
  etQ下传文?
  putQ上传文?
  exitQ退出ftpE序
  指oQpsftp-x86 187.136.5.1
  q时会问名字密码和要不要产生加密键|然后再用put和get来上下传文g

true 2007-07-30 11:03 发表评论
]]>
pȝ旉C、CQ+http://www.shnenglu.com/true/archive/2007/04/12/21709.htmltruetrueThu, 12 Apr 2007 04:04:00 GMThttp://www.shnenglu.com/true/archive/2007/04/12/21709.htmlhttp://www.shnenglu.com/true/comments/21709.htmlhttp://www.shnenglu.com/true/archive/2007/04/12/21709.html#Feedback1http://www.shnenglu.com/true/comments/commentRss/21709.htmlhttp://www.shnenglu.com/true/services/trackbacks/21709.html

C/C++中的日期和时?br>作者:日期和时?出处Q日期和旉 更新旉Q?2005q?9?5?br>摘要Q?br>本文从介l基概念入手Q探讨了在C/C++中对日期和时间操作所用到的数据结构和函数Qƈ对计时、时间的获取、时间的计算和显C格式等斚wq行了阐q。本文还通过大量的实例向你展CZtime.h头文件中声明的各U函数和数据l构的详l用方法?/p>

关键字:UTCQ世界标准时_QCalendar TimeQ日历时_QepochQ时间点Q,clock tickQ时钟计时单元)

1Q概?br>在C/C++中,对字W串的操作有很多值得注意的问题,同样QC/C++Ҏ间的操作也有许多值得大家注意的地斏V最q,在技术群中有很多|友也多ơ问到过C++语言中对旉的操作、获取和昄{等的问题。下面,在这文章中Q笔者将主要介绍在C/C++中时间和日期的用方?

通过学习许多C/C++库,你可以有很多操作、用时间的Ҏ。但在这之前你需要了解一?#8220;旉”?#8220;日期”的概念,主要有以下几个:

Coordinated Universal TimeQUTCQ:协调世界Ӟ又称Z界标准时_也就是大家所熟知的格林威L准时_Greenwich Mean TimeQGMTQ。比如,中国内地的时间与UTC的时差ؓ+8Q也是UTC+8。美国是UTC-5?/p>

Calendar TimeQ日历时_是用“从一个标准时间点到此时的旉l过的秒?#8221;来表C的旉。这个标准时间点对不同的~译器来说会有所不同Q但对一个编译系l来_q个标准旉Ҏ不变的,该编译系l中的时间对应的日历旉都通过该标准时间点来衡量,所以可以说日历旉?#8220;相对旉”Q但是无Z在哪一个时区,在同一时刻对同一个标准时间点来说Q日历时间都是一L?/p>

epochQ时间点。时间点在标准C/C++中是一个整敎ͼ它用此时的时间和标准旉点相差的U数Q即日历旉Q来表示?/p>

clock tickQ时钟计时单元(而不把它叫做旉滴答ơ数Q,一个时钟计时单元的旉长短是由CPU控制的。一个clock tick不是CPU的一个时钟周期,而是C/C++的一个基本计时单位?/p>

我们可以使用ANSI标准库中的time.h头文件。这个头文g中定义的旉和日期所使用的方法,无论是在l构定义Q还是命名,都具有明昄C语言风格。下面,我将说明在C/C++中怎样使用日期的时间功能?/p>

2Q?计时

C/C++中的计时函数是clock()Q而与其相关的数据cd是clock_t。在MSDN中,查得对clock函数定义如下Q?/p>

clock_t clock( void );

q个函数q回?#8220;开启这个程序进E?#8221;?#8220;E序中调用clock()函数”时之间的CPU旉计时单元Qclock tickQ数Q在MSDN中称之ؓ挂钟旉Qwal-clockQ。其中clock_t是用来保存时间的数据cdQ在time.h文g中,我们可以扑ֈ对它的定义:

#ifndef _CLOCK_T_DEFINED
typedef long clock_t;
#define _CLOCK_T_DEFINED
#endif

很明显,clock_t是一个长整Ş数。在time.h文g中,q定义了一个常量CLOCKS_PER_SECQ它用来表示一U钟会有多少个时钟计时单元,其定义如下:

#define CLOCKS_PER_SEC ((clock_t)1000)

可以看到每过千分之一U(1毫秒Q,调用clockQ)函数q回的值就?。下面D个例子,你可以用公式clock()/CLOCKS_PER_SEC来计一个进E自w的q行旉Q?/p>

void elapsed_time()
{
printf("Elapsed time:%u secs.\n",clock()/CLOCKS_PER_SEC);
}

当然Q你也可以用clock函数来计你的机器运行一个@环或者处理其它事件到底花了多时_

#include “stdio.h”
#include “stdlib.h”
#include “time.h”

int main( void )
{
long i = 10000000L;
clock_t start, finish;
double duration;
/* 量一个事件持l的旉*/
printf( "Time to do %ld empty loops is ", i );
start = clock();
while( i-- )
finish = clock();
duration = (double)(finish - start) / CLOCKS_PER_SEC;
printf( "%f seconds\n", duration );
system("pause");
}

在笔者的机器上,q行l果如下Q?/p>

Time to do 10000000 empty loops is 0.03000 seconds

上面我们看到旉计时单元的长度ؓ1毫秒Q那么计时的_ֺ也ؓ1毫秒Q那么我们可不可以通过改变CLOCKS_PER_SEC的定义,通过把它定义的大一些,从而计时_ֺ更高呢?通过试Q你会发现这h不行的。在标准C/C++中,最的计时单位是一毫秒?/p>

3Q与日期和时间相关的数据l构

在标准C/C++中,我们可通过tml构来获得日期和旉Qtml构在time.h中的定义如下Q?/p>

#ifndef _TM_DEFINED
struct tm {
int tm_sec; /* U?– 取值区间ؓ[0,59] */
int tm_min; /* ?- 取值区间ؓ[0,59] */
int tm_hour; /* ?- 取值区间ؓ[0,23] */
int tm_mday; /* 一个月中的日期 - 取值区间ؓ[1,31] */
int tm_mon; /* 月䆾Q从一月开始,0代表一月) - 取值区间ؓ[0,11] */
int tm_year; /* q䆾Q其值等于实际年份减?900 */
int tm_wday; /* 星期 – 取值区间ؓ[0,6]Q其?代表星期天,1代表星期一Q以此类?*/
int tm_yday; /* 从每q的1?日开始的天数 – 取值区间ؓ[0,365]Q其?代表1?日,1代表1?日,以此cL */
int tm_isdst; /* 夏o时标识符Q实行夏令时的时候,tm_isdst为正。不实行夏o时的q候,tm_isdst?Q不了解情况Ӟtm_isdst()?/
};
#define _TM_DEFINED
#endif

ANSI C标准UC用tml构的这U时间表CZؓ分解旉(broken-down time)?/p>

而日历时_Calendar TimeQ是通过time_t数据cd来表C的Q用time_t表示的时_日历旉Q是从一个时间点Q例如:1970q?????U)到此时的U数。在time.h中,我们也可以看到time_t是一个长整型敎ͼ

#ifndef _TIME_T_DEFINED
typedef long time_t; /* 旉?*/
#define _TIME_T_DEFINED /* 避免重复定义 time_t */
#endif

大家可能会生疑问:既然time_t实际上是长整型,到未来的某一天,从一个时间点Q一般是1970q?????U)到那时的U数Q即日历旉Q超Z长整形所能表C的数的范围怎么办?对time_t数据cd的值来_它所表示的时间不能晚?038q??8?9?4?7U。ؓ了能够表C更久远的时_一些编译器厂商引入?4位甚x长的整Ş数来保存日历旉。比如微软在Visual C++中采用了__time64_t数据cd来保存日历时_q过_time64()函数来获得日历时_而不是通过使用32位字的time()函数Q,q样可以通过该数据类型保?001q?????U(不包括该旉点)之前的时间?/p>

在time.h头文件中Q我们还可以看到一些函敎ͼ它们都是以time_t为参数类型或q回值类型的函数Q?/p>

double difftime(time_t time1, time_t time0);
time_t mktime(struct tm * timeptr);
time_t time(time_t * timer);
char * asctime(const struct tm * timeptr);
char * ctime(const time_t *timer);

此外Qtime.hq提供了两种不同的函数将日历旉Q一个用time_t表示的整敎ͼ转换为我们^时看到的把年月日时分U分开昄的时间格式tmQ?/p>

struct tm * gmtime(const time_t *timer);
struct tm * localtime(const time_t * timer);

通过查阅MSDNQ我们可以知道Microsoft C/C++ 7.0中时间点的|time_t对象的|是从1899q?2?1???U到该时间点所l过的秒敎ͼ而其它各U版本的Microsoft C/C++和所有不同版本的Visual C++都是计算的从1970q?????U到该时间点所l过的秒数?/p>

4Q与日期和时间相关的函数及应?br>在本节,我将向大家展C怎样利用time.h中声明的函数Ҏ间进行操作。这些操作包括取当前旉、计时间间隔、以不同的Ş式显C时间等内容?/p>

4.1 获得日历旉

我们可以通过time()函数来获得日历时_Calendar TimeQ,其原型ؓQ?/p>

time_t time(time_t * timer);

如果你已l声明了参数timerQ你可以从参数timerq回现在的日历时_同时也可以通过q回D回现在的日历旉Q即从一个时间点Q例如:1970q?????U)到现在此时的U数。如果参CؓI(NULQ,函数只通过q回D回现在的日历旉Q比如下面这个例子用来显C当前的日历旉Q?/p>

#include "time.h"
#include "stdio.h"
int main(void)
{
struct tm *ptr;
time_t lt;
lt =time(NUL);
printf("The Calendar Time now is %d\n",lt);
return 0;
}

q行的结果与当时的时间有养I我当时运行的l果是:

The Calendar Time now is 1122707619

其中1122707619是我运行程序时的日历时间。即?970q?????U到此时的秒数?/p>

4.2 获得日期和时?/p>

q里说的日期和时间就是我们^时所说的q、月、日、时、分、秒{信息。从W?节我们已l知道这些信息都保存在一个名为tm的结构体中,那么如何一个日历时间保存ؓ一个tml构的对象呢Q?/p>

其中可以使用的函数是gmtime()和localtime()Q这两个函数的原型ؓQ?/p>

struct tm * gmtime(const time_t *timer);
struct tm * localtime(const time_t * timer);

其中gmtime()函数是将日历旉转化Z界标准时_x林尼L_Qƈq回一个tml构体来保存q个旉Q而localtime()函数是将日历旉转化为本地时间。比如现在用gmtime()函数获得的世界标准时间是2005q??0??8?0U,那么我用localtime()函数在中国地得的本地旉会比世界标准旉?个小Ӟ?005q??0?5?8?0U。下面是个例子:

#include "time.h"
#include "stdio.h"
int main(void)
{
struct tm *local;
time_t t;
t=time(NUL);
local=localtime(&t);
printf("Local hour is: %d\n",local->tm_hour);
local=gmtime(&t);
printf("UTC hour is: %d\n",local->tm_hour);
return 0;
}

q行l果是:

Local hour is: 15
UTC hour is: 7

4.3 固定的时间格?/p>

我们可以通过asctime()函数和ctime()函数时间以固定的格式显C出来,两者的q回值都是char*型的字符丌Ӏ返回的旉格式为:

星期?月䆾 日期 ??U?q\n\0
例如QWed Jan 02 02:03:55 1980\n\0

其中\n是一个换行符Q\0是一个空字符Q表C字W串l束。下面是两个函数的原型:

char * asctime(const struct tm * timeptr);
char * ctime(const time_t *timer);

其中asctime()函数是通过tml构来生成具有固定格式的保存旉信息的字W串Q而ctime()是通过日历旉来生成时间字W串。这L话,asctimeQ)函数只是把tml构对象中的各个域填到时间字W串的相应位|就行了Q而ctimeQ)函数需要先参照本地的时间设|,把日历时间{化ؓ本地旉Q然后再生成格式化后的字W串。在下面Q如果t是一个非I的time_t变量的话Q那么:

printf(ctime(&t));

{h于:

struct tm *ptr;
ptr=localtime(&t);
printf(asctime(ptr));

那么Q下面这个程序的两条printf语句输出的结果就是不同的了(除非你将本地时区设ؓ世界标准旉所在的时区Q:

#include "time.h"
#include "stdio.h"
int main(void)
{
struct tm *ptr;
time_t lt;
lt =time(NUL);
ptr=gmtime(<);
printf(asctime(ptr));
printf(ctime(<));
return 0;
}

q行l果Q?/p>

Sat Jul 30 08:43:03 2005
Sat Jul 30 16:43:03 2005

4.4 自定义时间格?/p>

我们可以使用strftimeQ)函数时间格式化为我们想要的格式。它的原型如下:

size_t strftime(
char *strDest,
size_t maxsize,
const char *format,
const struct tm *timeptr
);

我们可以Ҏformat指向字符串中格式命o把timeptr中保存的旉信息攑֜strDest指向的字W串中,最多向strDest中存放maxsize个字W。该函数q回向strDest指向的字W串中放|的字符数?/p>

函数strftime()的操作有些类gsprintf()Q识别以癑ֈ?%)开始的格式命o集合Q格式化输出l果攑֜一个字W串中。格式化命o说明串strDest中各U日期和旉信息的确切表C方法。格式串中的其他字符原样放进串中。格式命令列在下面,它们是区分大写的?/p>

%a 星期几的?br>%A 星期几的全称
%b 月分的简?br>%B 月䆾的全U?br>%c 标准的日期的旉?br>%C q䆾的后两位数字
%d 十进制表C的每月的第几天
%D ??q?br>%e 在两字符域中Q十q制表示的每月的W几?br>%F q???br>%g q䆾的后两位数字Q用基于周的年
%G q分Q用基于周的年
%h 写的月䆾?br>%H 24时制的时
%I 12时制的时
%j 十进制表C的每年的第几天
%m 十进制表C的月䆾
%M 十时制表C的分钟?br>%n 新行W?br>%p 本地的AM或PM的等hC?br>%r 12时的时?br>%R 昄时和分钟:hh:mm
%S 十进制的U数
%t 水^制表W?br>%T 昄时分U:hh:mm:ss
%u 每周的第几天Q星期一为第一?Qg0?Q星期一?Q?br>%U W年的第几周Q把星期日做为第一天(g0?3Q?br>%V 每年的第几周Q用基于周的年
%w 十进制表C的星期几(g0?Q星期天?Q?br>%W 每年的第几周Q把星期一做ؓW一天(g0?3Q?br>%x 标准的日期串
%X 标准的时间串
%y 不带世纪的十q制q䆾Qg0?9Q?br>%Y 带世U部分的十进制年?br>%zQ?Z 时区名称Q如果不能得到时区名U则q回I字W?br>%% 癑ֈ?/p>

如果xC现在是几点了,q以12时制显C,p下面q段E序Q?/p>

#include “time.h”
#include “stdio.h”
int main(void)
{
struct tm *ptr;
time_t lt;
char str[80];
lt=time(NUL);
ptr=localtime(<);
strftime(str,100,"It is now %I %p",ptr);
printf(str);
return 0;
}

其运行结果ؓQ?br>It is now 4PM

而下面的E序则显C当前的完整日期Q?/p>

#include <stdio.h>
#include <time.h>

void main( void )
{
struct tm *newtime;
char tmpbuf[128];
time_t lt1;
time( <1 );
newtime=localtime(<1);
strftime( tmpbuf, 128, "Today is %A, day %d of %B in the year %Y.\n", newtime);
printf(tmpbuf);
}

q行l果Q?/p>

Today is Saturday, day 30 of July in the year 2005.

4.5 计算持箋旉的长?/p>

有时候在实际应用中要计算一个事件持l的旉长度Q比如计打字速度。在W?节计旉分中Q我已经用clock函数举了一个例子。Clock()函数可以_到毫U。同Ӟ我们也可以用difftime()函数Q但它只能精到U。该函数的定义如下:

double difftime(time_t time1, time_t time0);

虽然该函数返回的以秒计算的时间间隔是doublecd的,但这q不说明该时间具有同double一L_度,q是由它的参数觉得的Qtime_t是以Uؓ单位计算的)。比如下面一D늨序:

#include "time.h"
#include "stdio.h"
#include "stdlib.h"
int main(void)
{
time_t start,end;
start = time(NUL);
system("pause");
end = time(NUL);
printf("The pause used %f seconds.\n",difftime(end,start));//<-
system("pause");
return 0;
}

q行l果为:
hL键l? . .
The pause used 2.000000 seconds.
hL键l? . .

可以惛_Q暂停的旉q不那么巧是整整2U钟。其实,你将上面E序的带?#8220;//<-”注释的一行用下面的一行代码替换:

printf("The pause used %f seconds.\n",end-start);

其运行结果是一L?/p>

4.6 分解旉转化为日历时?/p>

q里说的分解旉是以年、月、日、时、分、秒{分量保存的旉l构Q在C/C++中是tml构。我们可以用mktimeQ)函数用tml构表示的时间{化ؓ日历旉。其函数原型如下Q?/p>

time_t mktime(struct tm * timeptr);

其返回值就是{化后的日历时间。这h们就可以先制定一个分解时_然后对这个时间进行操作了Q下面的例子可以计算?997q??日是星期几:

#include "time.h"
#include "stdio.h"
#include "stdlib.h"
int main(void)
{
struct tm t;
time_t t_of_day;
t.tm_year=1997-1900;
t.tm_mon=6;
t.tm_mday=1;
t.tm_hour=0;
t.tm_min=0;
t.tm_sec=1;
t.tm_isdst=0;
t_of_day=mktime(&t);
printf(ctime(&t_of_day));
return 0;
}

q行l果Q?/p>

Tue Jul 01 00:00:01 1997

现在注意了,有了mktime()函数Q是不是我们可以操作现在之前的Q何时间呢Q你可以通过q种办法出1945q??5h星期几吗Q答案是否定的。因个时间在1970q??日之前,所以在大多数编译器中,q样的程序虽然可以编译通过Q但q行时会异常l止?/p>

5Qȝ

本文介绍了标准C/C++中的有关日期和时间的概念Qƈ通过各种实例讲述了这些函数和数据l构的用方法。笔者认为,和时间相关的一些概忉|相当重要的,理解q些概念是理解各U时间格式的转换的基Q更是应用这些函数和数据l构的基?br>

 上面是{的,本h自己再加点,以备后用Q?br>
/* //旉格式化ؓ2007.07.02 14Q?0
 time_t tm_now ;
 time(&tm_now) ;
 char szTime[64]="";
 strftime(szTime,64,"%Y.%m.%d %H:%M",localtime(&tm_now));
 cout << szTime << endl;
 */



true 2007-04-12 12:04 发表评论
]]>
通用makefilehttp://www.shnenglu.com/true/archive/2007/04/05/21301.htmltruetrueThu, 05 Apr 2007 04:01:00 GMThttp://www.shnenglu.com/true/archive/2007/04/05/21301.htmlhttp://www.shnenglu.com/true/comments/21301.htmlhttp://www.shnenglu.com/true/archive/2007/04/05/21301.html#Feedback0http://www.shnenglu.com/true/comments/commentRss/21301.htmlhttp://www.shnenglu.com/true/services/trackbacks/21301.html

通用Makefile及部分解?/h2>

######################################
# Copyright (c) 1997 George Foot (george.foot@merton.ox.ac.uk)
# All rights reserved.
######################################
#目标Q可执行文档Q名Uͼ库(譬如stdcx,iostr,mysql{)Q头文g路径
DESTINATION := test
LIBS :=
INCLUDES := .


RM := rm -f
#C,CC或CPP文g的后~
PS=cpp
# GNU Make的隐含变量定?br>CC=g++
CPPFLAGS = -g -Wall -O3 -march=i486
CPPFLAGS += $(addprefix -I,$(INCLUDES))
CPPFLAGS += -MMD

#以下部分无需修改
SOURCE := $(wildcard *.$(PS))
OBJS := $(patsubst %.$(PS),%.o,$(SOURCE))
DEPS := $(patsubst %.o,%.d,$(OBJS))
MISSING_DEPS := $(filter-out $(wildcard $(DEPS)),$(DEPS))
MISSING_DEPS_SOURCES := $(wildcard $(patsubst %.d,%.$(PS),$(MISSING_DEPS)))

.PHONY : all deps objs clean rebuild

all : $(DESTINATION)

deps : $(DEPS)
        $(CC) -MM -MMD $(SOURCE)


objs : $(OBJS)

clean :
        @$(RM) *.o
        @$(RM) *.d
        @$(RM) $(DESTINATION)

rebuild: clean all

ifneq ($(MISSING_DEPS),)
$(MISSING_DEPS) :
        @$(RM) $(patsubst %.d,%.o,$@)
endif

-include $(DEPS)

$(DESTINATION) : $(OBJS)
        $(CC) -o $(DESTINATION) $(OBJS) $(addprefix -l,$(LIBS))
#l束

  • 原作者是Gorge FootQ写q个Makefile的时候还是一个学?
  • ":="赋|?="不同的是Q?:="在赋值的同时Q会赋D句中所有的变量地展开Q也是_A:=$(B)后,B的值的改变不再影响A
  • 隐含规则。GUN Make在不特别指定的情况下会用诸如以下编译命令:$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@Q这也是Z么这个Makefile最后一个命令没有添?(CPPFLAGS)的原因,因ؓ~省是包含这个变量的
  • 函数和变量很怼Q?$ (函数名,I格Q一列由逗号分隔的参?"
  • SOURCES = $(wildcard *.cpp) 列出工作目录下文件名满"*.cpp"条g的文Ӟ以空格分隔,q将列表赋给SOURCE变量
  • patsubst函数Q?个参数。功能是第三个参数中的每一(q格分隔)W合W一个参数描q的部分替换成第二个参数制定的?
  • addprefix函数Q?个参数。将源串Q第2个参敎ͼq格分隔)中的每一Ҏ加前~Q第1个参敎ͼ
  • filter-out函数Q?个参数。从W二串中qo掉包含在W一个串中的?
  • $(CC) -MM -MMD $(SOURCE) : Ҏ个源文g生成依赖(dependenceQMake通过依赖规则来判断是否需要重新编译某个文?Q?D"生成".d"文gQ?MM表示L depends里面的系l的头文?使用<>包含的头文g)Q若使用-M则全部包含,事实上,pȝ头文件被修改的可能性极,不需要执行依赖检查)
  • .PHONYQ不查后面制定各Ҏ否存在同名文?
  • ifneg...else...endifQMakefile中的条g语句
  • -include $(DEPS) : DEPS中的文g包含q来Q?-"表示忽略文g不存在的错误
  • @$(RM) *.o : 开头的"@"表示在Make的时候,不显C条命令(GNU Make~省是显C的)
  • all : 作ؓW一个出现的目标目QMake会将它作Z要和~省目("make"pC?make all")
  • deps : 只生成依赖文?.d文g)
  • objs : 为每一个源码程序生成或更新 '.d' 文g?.o'文g
  • clean : 删除所?.d','.o'和可执行文g
  • rebuild : clean然后重徏
  • 内部变量$@, $< $^ : 分别表示目标?:前面的部分,比如all)Q依靠列表(:后面的部分)中的W一个依靠文Ӟ所有依靠文?



true 2007-04-05 12:01 发表评论
]]>关于Linux下编写和~译E序的几个问?/title><link>http://www.shnenglu.com/true/archive/2007/04/05/21289.html</link><dc:creator>true</dc:creator><author>true</author><pubDate>Thu, 05 Apr 2007 02:34:00 GMT</pubDate><guid>http://www.shnenglu.com/true/archive/2007/04/05/21289.html</guid><wfw:comment>http://www.shnenglu.com/true/comments/21289.html</wfw:comment><comments>http://www.shnenglu.com/true/archive/2007/04/05/21289.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/true/comments/commentRss/21289.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/true/services/trackbacks/21289.html</trackback:ping><description><![CDATA[ <br>  · 闫健?#183;CPCW <br>   <br>    当前Q虽然Linuxq不很普?在Linux下编写和~译E序的h不多。但是我怿,随着Linux性能的不断提升和逐渐普及Q会有许多自pY件出玎ͼ也会有许多h成ؓLinux下的E序员。我l合自己的经验,介绍一下Linux下编写和~译E序所要注意的几个问题Q奉献给希望为Linux的发展作A献的Z?<br>   <br>   <br>  Linux下怎样~译E序Q?<br>   <br>  大多数LinuxE序都是由C语言~写的ƈ由GNU C~译而成。现在GCC是各U发行套件的一部分。有x新GCC~译器的版本、文章和补丁Lftp://ftp.gnu.org/pub/gnu/?<br>   <br>  由CQ+~写的程序必ȝGNU C++~译QGNU C++也是各种发行套g的一部分Q在以上|址也有最新版本和补丁?<br>   <br>  ~译2.0.x的内栔R?.7.2.x版本的GCCQ如用象GCC 2.8.x, EGCS, or PGCC别的~译器编译内核可能生不可预想的后果?<br>   <br>   <br>  怎样UL其它UnixE序到Linux上? <br>   <br>  d来说QUnix上的E序不需要做改动Q只要简单的按照提示可以移植到Linux上,如果安装q程中出现错误信息,而你又不知道怎么处理Q你可以猜或略去Q不q这样生的E序往往带有bug。所以最好还是问一下有l验的h?<br>   <br>  如果要从BSD-ishULE序Q试一试在~译时加?I/usr/include/bsd ?Qlbsd命o?<br>   <br>   <br>  什么是ld.so,从哪可以扑ֈ它? <br>   <br>  ld.so是动态函数库装蝲器。过去,使用׃n函数库的E序在原代码开头用约3K的空间来L和加载共享函数库Q现在,q段代码被加q了一个特D共享函数库/lib/ld.soQ所有的E序都可以用该׃n库,q样p省了盘I间Q而且升方便?<br>   <br>  ld.so可以从以下网址得到tsx-11.mit.edu/pub/linux/packages/GCC/?<br>   <br>   <br>  怎样升库函数而不使系l崩溃? <br>   <br>  注意Q进行此操作应该L做备份的习惯Q因Ҏ作很Ҏ出错?<br>   <br>  如果你升U象libc4q样的老函数库Q这个过E会变得非常困难。而且你应该在该系l上让libc4和libc5共存Q因为,有些老程序还需要它。升Ulibc5也一栗?<br>   <br>  升动态库的问题常出现在当你移走老的函数库时Q用来升U的E序也运行不了了。有许多Ҏ可以解决q个问题。一个方法就是暂时备份一下运行程序所需函数库,它们一般在/lib/?usr/lib/?/usr/local/lib/、或其它的地方,在文?etc/ld.so.conf中都有详l记录?<br>   <br>  例如Q当你升Ulibc5Ӟ目录/lib/中有如下文g <br>   <br>  libc.so.5 <br>   <br>  libc.so.5.4.33 <br>   <br>  libm.so.5 <br>   <br>  libm.so.5.0.9 <br>   <br>  q些是C函数库和数学库,拯它们到文?etc/ld.so.conf中含有的其它的目录,?usr/lib/中: <br>   <br>  cp -df /lib/libc.so.5* /usr/lib/ <br>   <br>  cp -df /lib/libm.so.5* /usr/lib/ <br>   <br>  ldconfig <br>   <br>  一定要Cq行ldconfig来升U函数库的配|文件?<br>   <br>  文glibc.so.5 ?libm.so.5是实际库文g的链接文Ӟ当你升的时候,如果老的链接文g存在Q新的链接不会生,除非你用CP命o?f选项。CP?d选项只复刉接文Ӟ不复制原文g?<br>   <br>  如果你需要直接覆盖链接,使用ln命o的选项-f?<br>   <br>  例如Q拷贝新的库函数覆盖旧的。先Ҏ的函数库做一个链接,然后把函数库和链接一h贝到/lib/中,命o如下Q?<br>   <br>  ln -sf ./libm.so.5.0.48 libm.so.5 <br>   <br>  ln -sf ./libc.so.5.0.48 libc.so.5 <br>   <br>  cp -df libm.so.5* /lib <br>   <br>  cp -df libc.so.5* /lib <br>   <br>  重申一下,拯完别忘记q行ldconfig. <br>   <br>  如果一切工作顺利的话,你可以删除老的函数库的备䆾?<br>   <br>   <br>  我能否把?86上编译的代码或编译器拿到386上用Q?<br>   <br>  当然Q除非你~译的是内核?<br>   <br>  GCC用来?86上编译的选项-m486 只是优化了所~译E序Q其运行快一些。这些编译的E序仍能很好的在386上运行,只是效果差一些?<br>   <br>  然而,从内?.3.35以后Q采?86或Pentium选项~译的内怸能用?86的机器?<br>   <br>  GCC可以针对386?86q行配置。两者区别在于,针对386配置的GCC?m386作ؓ~省选项Q而针?86配置的GCC?m486作ؓ~省选项Q仅此而已?<br>   <br>   <br>  gcc -O6可以q什么? <br>   <br>  目前Q它?-O2 (GCC 2.5) ?-O3 (GCC 2.6, 2.7)功能一P所有版本大于它的功能也一栗新版内核的Makefiles使用QO2Q所以你也应该用QO2?<br>   <br>   <br>  linux/*.h 和asm/*.h在什么地方? <br>   <br>  目录 /usr/include/linux/ ?/usr/include/asm/低下的文件是内核头文件的软链接,内核头文件其实在目录/usr/src/kernel*/低下?<br>   <br>   <br>  怎样作一个共享函数库Q?<br>   <br>  对ELF, 命o如下Q?<br>   <br>  gcc -fPIC -c *.c <br>   <br>  gcc -shared -Wl,-soname,libfoo.so.1 -o libfoo.so.1.0 *.o <br>   <br>  对a.outQ从 http://tsx-11.mit.edu/pub/linux/packages/GCC/src/ 下蝲n.nn.tar.gzQ其中包含详l说明。徏议你共享库由a.out升为ELF?<br>   <br>   <br>  Z么我~译的可执行E序非常大? <br>   <br>  用ELF~译器,生成可执行程序太大最可能的原因是没有合适的.so库与你用的库函数链接。对每一个象libc.so.5.2.18的函数库Q应该有一个象libc.so的链接?<br>   <br>  用a.out~译器,生成可执行程序太大可能是使用?g选项Q这会生成静态链接库而不是动态链接库?<br>   <br>   <br>  从哪可以得到对于Linux?#8216;lint’Q?<br>   <br>  大部?#8216;lint’的功能已l内|进了GCCQ打开GCC?Wall选项会打开许多有用的外部警告?<br>   <br>  q有一个叫`lclint'的Y件功能和传统的lint差不多,原代码可以在http://larch.lcs.mit.edu /pub/Larch/lclint/中找到?<br>    做h要厚道,h明{自酷|动?www.ASPCOOL.COM)?<br> <img src ="http://www.shnenglu.com/true/aggbug/21289.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/true/" target="_blank">true</a> 2007-04-05 10:34 <a href="http://www.shnenglu.com/true/archive/2007/04/05/21289.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>在Linux中创建静态库和动态库 【{?/title><link>http://www.shnenglu.com/true/archive/2007/04/04/21256.html</link><dc:creator>true</dc:creator><author>true</author><pubDate>Wed, 04 Apr 2007 10:22:00 GMT</pubDate><guid>http://www.shnenglu.com/true/archive/2007/04/04/21256.html</guid><wfw:comment>http://www.shnenglu.com/true/comments/21256.html</wfw:comment><comments>http://www.shnenglu.com/true/archive/2007/04/04/21256.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/true/comments/commentRss/21256.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/true/services/trackbacks/21256.html</trackback:ping><description><![CDATA[<p style="TEXT-INDENT: 20pt">我们通常把一些公用函数制作成函数库,供其它程序用。函数库分ؓ静态库和动态库两种。静态库在程序编译时会被q接到目标代码中Q程序运行时不再需要该静态库。动态库在程序编译时q不会被q接到目标代码中Q而是在程序运行是才被载入Q因此在E序q行时还需要动态库存在。本文主要通过举例来说明在Linux中如何创建静态库和动态库Q以及用它们?</p> <p style="TEXT-INDENT: 20pt">在创建函数库前,我们先来准备举例用的源程序,q将函数库的源程序编译成.o文g?</p> <p style="TEXT-INDENT: 20pt">W?步:~辑得到举例的程?-hello.h、hello.c和main.cQ?</p> <p style="TEXT-INDENT: 20pt">hello.c(见程?)是函数库的源E序Q其中包含公用函数helloQ该函数在屏幕上输?Hello XXX!"。hello.h(见程?)函数库的头文件。main.c(见程?)为测试库文g的主E序Q在ȝ序中调用了公用函数hello?</p>  #ifndef HELLO_H<br> #define HELLO_H<br> <br> void hello(const char *name);<br> <br> #endif //HELLO_H<br> E序1: hello.h<br> <br> #include <stdio.h><br> <br> void hello(const char *name)<br> {<br>  printf("Hello %s!\n", name);<br> }<br> E序2: hello.c<br> <br> #include "hello.h"<br> <br> int main()<br> {<br>  hello("everyone");<br>  return 0;<br> }<br> E序3: main.c<br> <p style="TEXT-INDENT: 20pt">W?步:hello.c~译?o文gQ?</p> <p style="TEXT-INDENT: 20pt">无论静态库Q还是动态库Q都是由.o文g创徏的。因此,我们必须源E序hello.c通过gcc先编译成.o文g?</p> <p style="TEXT-INDENT: 20pt">在系l提C符下键入以下命令得到hello.o文g?</p> <p style="TEXT-INDENT: 40pt"># gcc -c hello.c </p> <p style="TEXT-INDENT: 40pt"># </p> <p style="TEXT-INDENT: 20pt">(?Q本文不介绍各命令用和其参数功能,若希望详l了解它们,请参考其他文档? </p> <p style="TEXT-INDENT: 20pt">(?Q首字符"#"是系l提C符Q不需要键入,下文相同? </p> <p style="TEXT-INDENT: 20pt">我们q行ls命o看看是否生存了hello.o文g?</p> <p style="TEXT-INDENT: 40pt"># ls </p> <p style="TEXT-INDENT: 40pt">hello.c hello.h hello.o main.c </p> <p style="TEXT-INDENT: 40pt"># </p> <p style="TEXT-INDENT: 20pt">(?Q首字符不是"#"为系l运行结果,下文相同? </p> <p style="TEXT-INDENT: 20pt">在ls命ol果中,我们看到了hello.o文gQ本步操作完成?</p> <p style="TEXT-INDENT: 20pt">下面我们先来看看如何创徏静态库Q以及用它?</p> <p style="TEXT-INDENT: 20pt">W?步:?o文g创徏静态库Q?</p> <p style="TEXT-INDENT: 20pt">静态库文g名的命名规范是以lib为前~Q紧接着跟静态库名,扩展名ؓ.a。例如:我们创建的静态库名ؓmyhelloQ则静态库文g名就是libmyhello.a。在创徏和用静态库Ӟ需要注意这炏V创建静态库用ar命o?</p> <p style="TEXT-INDENT: 20pt">在系l提C符下键入以下命令将创徏静态库文glibmyhello.a?</p> <p style="TEXT-INDENT: 40pt"># ar cr libmyhello.a hello.o </p> <p style="TEXT-INDENT: 40pt"># </p> <p style="TEXT-INDENT: 20pt">我们同样q行ls命o查看l果Q?</p> <p style="TEXT-INDENT: 40pt"># ls </p> <p style="TEXT-INDENT: 40pt">hello.c hello.h hello.o libmyhello.a main.c </p> <p style="TEXT-INDENT: 40pt"># </p> <p style="TEXT-INDENT: 20pt">ls命ol果中有libmyhello.a?</p> <p style="TEXT-INDENT: 20pt">W?步:在程序中使用静态库Q?</p> <p style="TEXT-INDENT: 20pt">静态库制作完了Q如何用它内部的函数呢Q只需要在使用到这些公用函数的源程序中包含q些公用函数的原型声明,然后在用gcc命o生成目标文g时指明静态库名,gcc会从静态库中将公用函数q接到目标文件中。注意,gcc会在静态库名前加上前缀libQ然后追加扩展名.a得到的静态库文g名来查找静态库文g?</p> <p style="TEXT-INDENT: 20pt">在程?:main.c中,我们包含了静态库的头文ghello.hQ然后在ȝ序main中直接调用公用函数hello。下面先生成目标E序helloQ然后运行helloE序看看l果如何?</p> <p style="TEXT-INDENT: 40pt"># gcc -o hello main.c -L. -lmyhello </p> <p style="TEXT-INDENT: 40pt"># ./hello </p> <p style="TEXT-INDENT: 40pt">Hello everyone! </p> <p style="TEXT-INDENT: 40pt"># </p> <p style="TEXT-INDENT: 20pt">我们删除静态库文g试试公用函数hello是否真的q接到目标文?hello中了?</p> <p style="TEXT-INDENT: 40pt"># rm libmyhello.a </p> <p style="TEXT-INDENT: 40pt">rm: remove regular file `libmyhello.a'? y </p> <p style="TEXT-INDENT: 40pt"># ./hello </p> <p style="TEXT-INDENT: 40pt">Hello everyone! </p> <p style="TEXT-INDENT: 40pt"># </p> <p style="TEXT-INDENT: 20pt">E序照常q行Q静态库中的公用函数已经q接到目标文件中了?</p> <p style="TEXT-INDENT: 20pt">我们l箋看看如何在Linux中创建动态库。我们还是从.o文g开始?</p> <p style="TEXT-INDENT: 20pt">W?步:?o文g创徏动态库文gQ?</p> <p style="TEXT-INDENT: 20pt">动态库文g名命名规范和静态库文g名命名规范类|也是在动态库名增加前~libQ但其文件扩展名?so。例如:我们创建的动态库名ؓmyhelloQ则动态库文g名就是libmyhello.so。用gcc来创建动态库?</p> <p style="TEXT-INDENT: 20pt">在系l提C符下键入以下命令得到动态库文glibmyhello.so?</p> <p style="TEXT-INDENT: 40pt"># gcc -shared -fPCI -o libmyhello.so hello.o </p> <p style="TEXT-INDENT: 40pt"># </p> <p style="TEXT-INDENT: 20pt">我们照样使用ls命o看看动态库文g是否生成?</p> <p style="TEXT-INDENT: 40pt"># ls </p> <p style="TEXT-INDENT: 40pt">hello.c hello.h hello.o libmyhello.so main.c </p> <p style="TEXT-INDENT: 40pt"># </p> <p style="TEXT-INDENT: 20pt">W?步:在程序中使用动态库Q?</p> <p style="TEXT-INDENT: 20pt">在程序中使用动态库和用静态库完全一P也是在用到q些公用函数的源E序中包含这些公用函数的原型声明Q然后在用gcc命o生成目标文g时指明动态库名进行编译。我们先q行gcc命o生成目标文gQ再q行它看看结果?</p> <p style="TEXT-INDENT: 40pt"># gcc -o hello main.c -L. -lmyhello </p> <p style="TEXT-INDENT: 40pt"># ./hello </p> <p style="TEXT-INDENT: 40pt">./hello: error while loading shared libraries: libmyhello.so: cannot open shared object file: No such file or directory </p> <p style="TEXT-INDENT: 40pt"># </p> <p style="TEXT-INDENT: 20pt">哦!出错了。快看看错误提示Q原来是找不到动态库文glibmyhello.so。程序在q行Ӟ会在/usr/lib?lib{目录中查找需要的动态库文g。若扑ֈQ则载入动态库Q否则将提示cM上述错误而终止程序运行。我们将文glibmyhello.so复制到目?usr/lib中,再试试?</p> <p style="TEXT-INDENT: 40pt"># mv libmyhello.so /usr/lib </p> <p style="TEXT-INDENT: 40pt"># ./hello </p> <p style="TEXT-INDENT: 40pt">Hello everyone! </p> <p style="TEXT-INDENT: 40pt"># </p> <p style="TEXT-INDENT: 20pt">成功了。这也进一步说明了动态库在程序运行时是需要的?</p> <p style="TEXT-INDENT: 20pt">我们回过头看看,发现使用静态库和用动态库~译成目标程序用的gcc命o完全一P那当静态库和动态库同名Ӟgcc命o会用哪个库文g呢?q寚w题必I到底的心情Q来试试看?</p> <p style="TEXT-INDENT: 20pt">先删除除.c?h外的所有文Ӟ恢复成我们刚刚编辑完举例E序状态?</p> <p style="TEXT-INDENT: 40pt"># rm -f hello hello.o /usr/lib/libmyhello.so </p> <p style="TEXT-INDENT: 40pt"># ls </p> <p style="TEXT-INDENT: 40pt">hello.c hello.h main.c </p> <p style="TEXT-INDENT: 40pt"># </p> <p style="TEXT-INDENT: 20pt">在来创徏静态库文glibmyhello.a和动态库文glibmyhello.so?</p> <p style="TEXT-INDENT: 40pt"># gcc -c hello.c </p> <p style="TEXT-INDENT: 40pt"># ar cr libmyhello.a hello.o </p> <p style="TEXT-INDENT: 40pt"># gcc -shared -fPCI -o libmyhello.so hello.o </p> <p style="TEXT-INDENT: 40pt"># ls </p> <p style="TEXT-INDENT: 40pt">hello.c hello.h hello.o libmyhello.a libmyhello.so main.c </p> <p style="TEXT-INDENT: 40pt"># </p> <p style="TEXT-INDENT: 20pt">通过上述最后一条ls命oQ可以发现静态库文glibmyhello.a和动态库文glibmyhello.so都已l生成,q在当前目录中。然后,我们q行gcc命o来用函数库myhello生成目标文ghelloQƈq行E序 hello?</p> <p style="TEXT-INDENT: 40pt"># gcc -o hello main.c -L. -lmyhello </p> <p style="TEXT-INDENT: 40pt"># ./hello </p> <p style="TEXT-INDENT: 40pt">./hello: error while loading shared libraries: libmyhello.so: cannot open shared object file: No such file or directory </p> <p style="TEXT-INDENT: 40pt"># </p> <p style="TEXT-INDENT: 20pt">从程序helloq行的结果中很容易知道,当静态库和动态库同名Ӟ gcc命o优先用动态库?</p> <img src ="http://www.shnenglu.com/true/aggbug/21256.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/true/" target="_blank">true</a> 2007-04-04 18:22 <a href="http://www.shnenglu.com/true/archive/2007/04/04/21256.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>q程和线E编E-linux斚wQ{http://www.shnenglu.com/true/archive/2007/03/27/20712.htmltruetrueTue, 27 Mar 2007 08:28:00 GMThttp://www.shnenglu.com/true/archive/2007/03/27/20712.htmlhttp://www.shnenglu.com/true/comments/20712.htmlhttp://www.shnenglu.com/true/archive/2007/03/27/20712.html#Feedback0http://www.shnenglu.com/true/comments/commentRss/20712.htmlhttp://www.shnenglu.com/true/services/trackbacks/20712.html阅读全文

true 2007-03-27 16:28 发表评论
]]>
Linux环境q程间通信[转]http://www.shnenglu.com/true/archive/2007/03/27/20711.htmltruetrueTue, 27 Mar 2007 08:26:00 GMThttp://www.shnenglu.com/true/archive/2007/03/27/20711.htmlhttp://www.shnenglu.com/true/comments/20711.htmlhttp://www.shnenglu.com/true/archive/2007/03/27/20711.html#Feedback0http://www.shnenglu.com/true/comments/commentRss/20711.htmlhttp://www.shnenglu.com/true/services/trackbacks/20711.html

Linux环境q程间通信Q三Q?/h1>

消息队列

developerWorks
 

未显C需?JavaScript 的文档选项



U别: 初

郑R?/font> (mlinux@163.com)国防U大计算机学?br />

2003 q?1 ?17 ?/p>

本系列文章中的前两部分,我们探讨道及信号两U通信机制Q本文将深入W三部分Q介l系l?V 消息队列及其相应 API?/blockquote>

消息队列Q也叫做报文队列Q能够克服早期unix通信机制的一些缺炏V作为早期unix通信机制之一的信可够传送的信息量有限,后来虽然POSIX 1003.1b在信L实时性方面作了拓q,使得信号在传递信息量斚w有了相当E度的改q,但是信号q种通信方式更像"x"的通信方式Q它要求接受信号的进E在某个旉范围内对信号做出反应Q因此该信号最多在接受信号q程的生命周期内才有意义Q信h传递的信息是接q于随进E持l的概念Qprocess-persistentQ,?附录 1Q管道及有名道及有名管道则是典型的随进E持lIPCQƈ且,只能传送无格式的字节流无疑会给应用E序开发带来不便,另外Q它的缓冲区大小也受到限制?

消息队列是一个消息的链表。可以把消息看作一个记录,h特定的格式以及特定的优先U。对消息队列有写权限的进E可以向中按照一定的规则d新消息;Ҏ息队列有L限的q程则可以从消息队列中读走消息。消息队列是随内核持l的Q参?附录 1Q?

目前主要有两U类型的消息队列QPOSIX消息队列以及pȝV消息队列Q系lV消息队列目前被大量用。考虑到程序的可移植性,新开发的应用E序应尽量用POSIX消息队列?/p>

在本pd专题的序Q深ȝ解Linuxq程间通信QIPCQ)中,提到对于消息队列、信L、以及共享内存区来说Q有两个实现版本QPOSIX的以及系lV的。Linux内核Q内?.4.18Q支持POSIX信号灯、POSIX׃n内存Z及POSIX消息队列Q但对于LLinux发行版本之一redhad8.0Q内?.4.18Q,q没有提供对POSIXq程间通信API的支持,不过应该只是旉上的事?/p>

因此Q本文将主要介绍pȝV消息队列及其相应API?在没有声明的情况下,以下讨论中指的都是系lV消息队列?/b>

一、消息队列基本概?/span>

  1. pȝV消息队列是随内核持箋的,只有在内栔Rh者显C删除一个消息队列时Q该消息队列才会真正被删除。因此系l中记录消息队列的数据结构(struct ipc_ids msg_idsQ位于内怸Q系l中的所有消息队列都可以在结构msg_ids中找到访问入口?
  2. 消息队列是一个消息的链表。每个消息队列都有一个队列头Q用l构struct msg_queue来描qͼ参见 附录 2Q。队列头中包含了该消息队列的大量信息Q包括消息队列键倹{用户ID、组ID、消息队列中消息数目{等Q甚臌录了最q对消息队列dq程的ID。读者可以访问这些信息,也可以设|其中的某些信息?
  3. 下图说明了内怸消息队列是怎样建立赯pȝQ?
    其中Qstruct ipc_ids msg_ids是内怸记录消息队列的全局数据l构Qstruct msg_queue是每个消息队列的队列头?


从上囑֏以看出,全局数据l构 struct ipc_ids msg_ids 可以讉K到每个消息队列头的第一个成员:struct kern_ipc_permQ而每个struct kern_ipc_perm能够与具体的消息队列对应h是因为在该结构中Q有一个key_tcd成员keyQ而key则唯一定一个消息队列。kern_ipc_perml构如下Q?/p>
struct kern_ipc_perm{   //内核中记录消息队列的全局数据l构msg_ids能够讉K到该l构Q?
            key_t   key;    //该键值则唯一对应一个消息队?
            uid_t   uid;
            gid_t   gid;
uid_t   cuid;
gid_t   cgid;
mode_t  mode;
unsigned long seq;
}





回页?/font>


二、操作消息队?/span>

Ҏ息队列的操作无非有下面三U类型:

1?打开或创建消息队?
消息队列的内核持l性要求每个消息队列都在系l范围内对应唯一的键|所以,要获得一个消息队列的描述字,只需提供该消息队列的键值即可;

注:消息队列描述字是由在pȝ范围内唯一的键值生成的Q而键值可以看作对应系l内的一条\l?/p>

2?d操作

消息d操作非常单,对开发h员来_每个消息都类似如下的数据l构Q?/p>
struct msgbuf{
long mtype;
char mtext[1];
};

mtype成员代表消息cdQ从消息队列中读取消息的一个重要依据就是消息的cdQmtext是消息内容,当然长度不一定ؓ1。因此,对于发送消息来_首先预置一个msgbuf~冲区ƈ写入消息cd和内容,调用相应的发送函数即可;对读取消息来_首先分配q样一个msgbuf~冲区,然后把消息读入该~冲区即可?/p>

3?获得或设|消息队列属性:

消息队列的信息基本上都保存在消息队列头中Q因此,可以分配一个类g消息队列头的l构(struct msqid_dsQ见 附录 2)Q来q回消息队列的属性;同样可以讄该数据结构?






消息队列API

1、文件名到键?/strong>

#include <sys/types.h>
#include <sys/ipc.h>
key_t ftok (char*pathname, char proj)Q?


它返回与路径pathname相对应的一个键倹{该函数不直接对消息队列操作Q但在调用ipc(MSGGET,?或msgget()来获得消息队列描q字前,往往要调用该函数。典型的调用代码是:

key=ftok(path_ptr, 'a');
    ipc_id=ipc(MSGGET, (int)key, flags,0,NULL,0);
    ?


2、linux为操作系lVq程间通信的三U方式(消息队列、信L、共享内存区Q提供了一个统一的用L面:
int ipc (unsigned int call, int first, int second, int third, void * ptr, long fifth);

W一个参数指明对IPC对象的操作方式,Ҏ息队列而言共有四种操作QMSGSND、MSGRCV、MSGGET以及MSGCTLQ分别代表向消息队列发送消息、从消息队列d消息、打开或创建消息队列、控制消息队列;first参数代表唯一的IPC对象Q下面将介绍四种操作?/p>

  • int ipc( MSGGET, intfirst, intsecond, intthird, void*ptr, longfifth);
    与该操作对应的系lV调用为:int msgget( (key_t)firstQsecond)?
  • int ipc( MSGCTL, intfirst, intsecond, intthird, void*ptr, longfifth)
    与该操作对应的系lV调用为:int msgctl( firstQsecond, (struct msqid_ds*) ptr)?
  • int ipc( MSGSND, intfirst, intsecond, intthird, void*ptr, longfifth);
    与该操作对应的系lV调用为:int msgsnd( first, (struct msgbuf*)ptr, second, third)?
  • int ipc( MSGRCV, intfirst, intsecond, intthird, void*ptr, longfifth);
    与该操作对应的系lV调用为:int msgrcv( firstQ?struct msgbuf*)ptr, second, fifth,third)Q?

注:本h不主张采用系l调用ipc()Q而更們֐于采用系lV或者POSIXq程间通信API。原因如下:

  • 虽然该系l调用提供了l一的用L面,但正是由于这个特性,它的参数几乎不能l出特定的实际意义(如以first、second来命名参敎ͼQ在一定程度上造成开发不ѝ?
  • 正如ipc手册所说的Qipc()是linux所Ҏ的,~写E序时应注意E序的移植性问题;
  • 该系l调用的实现不过是把pȝV IPC函数q行了封装,没有M效率上的优势Q?
  • pȝV在IPC斚w的API数量不多QŞ式也较简z?

3.pȝV消息队列API
pȝV消息队列API共有四个Q用时需要包括几个头文gQ?

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>


1Qint msgget(key_t key, int msgflg)

参数key是一个键|由ftok获得Qmsgflg参数是一些标志位。该调用q回与健值key相对应的消息队列描述字?/p>

在以下两U情况下Q该调用创Z个新的消息队列:

  • 如果没有消息队列与健值key相对应,q且msgflg中包含了IPC_CREAT标志位;
  • key参数为IPC_PRIVATEQ?

参数msgflg可以Z下:IPC_CREAT、IPC_EXCL、IPC_NOWAIT或三者的或结果?/p>

调用q回Q?/b>成功q回消息队列描述字,否则q回-1?

注:参数key讄成常数IPC_PRIVATEq不意味着其他q程不能讉K该消息队列,只意味着卛_创徏新的消息队列?/p>

2Qint msgrcv(int msqid, struct msgbuf *msgp, int msgsz, long msgtyp, int msgflg);
该系l调用从msgid代表的消息队列中d一个消息,q把消息存储在msgp指向的msgbufl构中?

msqid为消息队列描q字Q消息返回后存储在msgp指向的地址Qmsgsz指定msgbuf的mtext成员的长度(x息内容的长度Q,msgtyp求读取的消息cdQ读消息标志msgflg可以Z下几个常值的或:

  • IPC_NOWAIT 如果没有满条g的消息,调用立即q回Q此Ӟerrno=ENOMSG
  • IPC_EXCEPT 与msgtyp>0配合使用Q返回队列中W一个类型不为msgtyp的消?
  • IPC_NOERROR 如果队列中满x件的消息内容大于所h的msgsz字节Q则把该消息截断Q截断部分将丢失?

msgrcv手册中详l给Z消息cd取不同值时(>0; <0; =0)Q调用将q回消息队列中的哪个消息?/p>

msgrcv()解除d的条件有三个Q?/p>

  1. 消息队列中有了满x件的消息Q?
  2. msqid代表的消息队列被删除Q?
  3. 调用msgrcvQ)的进E被信号中断Q?

调用q回Q?/b>成功q回d消息的实际字节数Q否则返?1?

3Qint msgsnd(int msqid, struct msgbuf *msgp, int msgsz, int msgflg);
向msgid代表的消息队列发送一个消息,卛_发送的消息存储在msgp指向的msgbufl构中,消息的大由msgze指定?

对发送消息来_有意义的msgflg标志为IPC_NOWAITQ指明在消息队列没有_I间容纳要发送的消息Ӟmsgsnd是否{待。造成msgsnd(){待的条件有两种Q?/p>

  • 当前消息的大与当前消息队列中的字节C和超q了消息队列的d量;
  • 当前消息队列的消息数Q单??Q不于消息队列的d量(单位"字节?Q,此时Q虽然消息队列中的消息数目很多,但基本上都只有一个字节?

msgsnd()解除d的条件有三个Q?
  1. 不满上qC个条Ӟx息队列中有容U消息的空_
  2. msqid代表的消息队列被删除Q?
  3. 调用msgsndQ)的进E被信号中断Q?

调用q回Q?/b>成功q回0Q否则返?1?

4Qint msgctl(int msqid, int cmd, struct msqid_ds *buf);
该系l调用对由msqid标识的消息队列执行cmd操作Q共有三Ucmd操作QIPC_STAT、IPC_SET 、IPC_RMID?

  1. IPC_STATQ该命o用来获取消息队列信息Q返回的信息存贮在buf指向的msqidl构中;
  2. IPC_SETQ该命o用来讄消息队列的属性,要设|的属性存储在buf指向的msqidl构中;可设|属性包括:msg_perm.uid、msg_perm.gid、msg_perm.mode以及msg_qbytesQ同Ӟ也媄响msg_ctime成员?
  3. IPC_RMIDQ删除msqid标识的消息队列;

调用q回Q?/b>成功q回0Q否则返?1?





回页?/font>


三、消息队列的限制

每个消息队列的容量(所能容U的字节敎ͼ都有限制Q该值因pȝ不同而不同。在后面的应用实例中Q输Zredhat 8.0的限Ӟl果参见 附录 3?

另一个限制是每个消息队列所能容U的最大消息数Q在redhad 8.0中,该限制是受消息队列容量制U的Q消息个数要于消息队列的容量(字节敎ͼ?/p>

注:上述两个限制是针Ҏ个消息队列而言的,pȝҎ息队列的限制q有pȝ范围内的最大消息队列个敎ͼ以及整个pȝ范围内的最大消息数。一般来_实际开发过E中不会过q个限制?/p>



回页?/font>


四、消息队列应用实?/span>

消息队列应用相对较简单,下面实例基本上覆盖了Ҏ息队列的所有操作,同时Q程序输出结果有助于加深对前面所讲的某些规则及消息队列限制的理解?/p>
#include <sys/types.h>
#include <sys/msg.h>
#include <unistd.h>
void msg_stat(int,struct msqid_ds );
main()
{
int gflags,sflags,rflags;
key_t key;
int msgid;
int reval;
struct msgsbuf{
        int mtype;
        char mtext[1];
    }msg_sbuf;
struct msgmbuf
    {
    int mtype;
    char mtext[10];
    }msg_rbuf;
struct msqid_ds msg_ginfo,msg_sinfo;
char* msgpath="/unix/msgqueue";
key=ftok(msgpath,'a');
gflags=IPC_CREAT|IPC_EXCL;
msgid=msgget(key,gflags|00666);
if(msgid==-1)
{
    printf("msg create error\n");
    return;
}
//创徏一个消息队列后Q输出消息队列缺省属?
msg_stat(msgid,msg_ginfo);
sflags=IPC_NOWAIT;
msg_sbuf.mtype=10;
msg_sbuf.mtext[0]='a';
reval=msgsnd(msgid,&msg_sbuf,sizeof(msg_sbuf.mtext),sflags);
if(reval==-1)
{
    printf("message send error\n");
}
//发送一个消息后Q输出消息队列属?
msg_stat(msgid,msg_ginfo);
rflags=IPC_NOWAIT|MSG_NOERROR;
reval=msgrcv(msgid,&msg_rbuf,4,10,rflags);
if(reval==-1)
    printf("read msg error\n");
else
    printf("read from msg queue %d bytes\n",reval);
//从消息队列中d消息后,输出消息队列属?
msg_stat(msgid,msg_ginfo);
msg_sinfo.msg_perm.uid=8;//just a try
msg_sinfo.msg_perm.gid=8;//
msg_sinfo.msg_qbytes=16388;
//此处验证用户可以更改消息队列的缺省msg_qbytes
//注意q里讄的值大于缺省?
reval=msgctl(msgid,IPC_SET,&msg_sinfo);
if(reval==-1)
{
    printf("msg set info error\n");
    return;
}
msg_stat(msgid,msg_ginfo);
//验证讄消息队列属?
reval=msgctl(msgid,IPC_RMID,NULL);//删除消息队列
if(reval==-1)
{
    printf("unlink msg queue error\n");
    return;
}
}
void msg_stat(int msgid,struct msqid_ds msg_info)
{
int reval;
sleep(1);//只是Z后面输出旉的方?
reval=msgctl(msgid,IPC_STAT,&msg_info);
if(reval==-1)
{
    printf("get msg info error\n");
    return;
}
printf("\n");
printf("current number of bytes on queue is %d\n",msg_info.msg_cbytes);
printf("number of messages in queue is %d\n",msg_info.msg_qnum);
printf("max number of bytes on queue is %d\n",msg_info.msg_qbytes);
//每个消息队列的容量(字节敎ͼ都有限制MSGMNBQ值的大小因系l而异。在创徏新的消息队列Ӟ//msg_qbytes的缺省值就是MSGMNB
printf("pid of last msgsnd is %d\n",msg_info.msg_lspid);
printf("pid of last msgrcv is %d\n",msg_info.msg_lrpid);
printf("last msgsnd time is %s", ctime(&(msg_info.msg_stime)));
printf("last msgrcv time is %s", ctime(&(msg_info.msg_rtime)));
printf("last change time is %s", ctime(&(msg_info.msg_ctime)));
printf("msg uid is %d\n",msg_info.msg_perm.uid);
printf("msg gid is %d\n",msg_info.msg_perm.gid);
}

E序输出l果?附录 3?




回页?/font>


结Q?/span>

消息队列与管道以及有名管道相比,h更大的灵zL,首先Q它提供有格式字节流Q有利于减少开发h员的工作量;其次Q消息具有类型,在实际应用中Q可作ؓ优先U用。这两点是管道以及有名管道所不能比的。同P消息队列可以在几个进E间复用Q而不这几个q程是否h亲缘关系Q这一点与有名道很相|但消息队列是随内核持l的Q与有名道Q随q程持箋Q相比,生命力更强,应用I间更大?/p>

附录 1Q?在参考文献[1]中,l出了IPC随进E持l、随内核持箋以及随文件系l持l的定义Q?

  1. 随进E持l:IPC一直存在到打开IPC对象的最后一个进E关闭该对象为止。如道和有名管道;
  2. 随内核持l:IPC一直持l到内核重新自D或者显C删除该对象为止。如消息队列、信L以及׃n内存{;
  3. 随文件系l持l:IPC一直持l到昄删除该对象ؓ止?

附录 2Q?
l构msg_queue用来描述消息队列_存在于系l空_

struct msg_queue {
    struct kern_ipc_perm q_perm;
    time_t q_stime;         /* last msgsnd time */
    time_t q_rtime;         /* last msgrcv time */
    time_t q_ctime;         /* last change time */
    unsigned long q_cbytes;     /* current number of bytes on queue */
    unsigned long q_qnum;       /* number of messages in queue */
    unsigned long q_qbytes;     /* max number of bytes on queue */
    pid_t q_lspid;          /* pid of last msgsnd */
    pid_t q_lrpid;          /* last receive pid */
    struct list_head q_messages;
    struct list_head q_receivers;
    struct list_head q_senders;
};


l构msqid_ds用来讄或返回消息队列的信息Q存在于用户I间Q?/p>
struct msqid_ds {
    struct ipc_perm msg_perm;
    struct msg *msg_first;      /* first message on queue,unused  */
    struct msg *msg_last;       /* last message in queue,unused */
    __kernel_time_t msg_stime;  /* last msgsnd time */
    __kernel_time_t msg_rtime;  /* last msgrcv time */
    __kernel_time_t msg_ctime;  /* last change time */
    unsigned long  msg_lcbytes; /* Reuse junk fields for 32 bit */
    unsigned long  msg_lqbytes; /* ditto */
    unsigned short msg_cbytes;  /* current number of bytes on queue */
    unsigned short msg_qnum;    /* number of messages in queue */
    unsigned short msg_qbytes;  /* max number of bytes on queue */
    __kernel_ipc_pid_t msg_lspid;   /* pid of last msgsnd */
    __kernel_ipc_pid_t msg_lrpid;   /* last receive pid */
};

//可以看出上述两个l构很相伹{?

附录 3Q?消息队列实例输出l果Q?

current number of bytes on queue is 0
number of messages in queue is 0
max number of bytes on queue is 16384
pid of last msgsnd is 0
pid of last msgrcv is 0
last msgsnd time is Thu Jan  1 08:00:00 1970
last msgrcv time is Thu Jan  1 08:00:00 1970
last change time is Sun Dec 29 18:28:20 2002
msg uid is 0
msg gid is 0
//上面刚刚创徏一个新消息队列时的输出
current number of bytes on queue is 1
number of messages in queue is 1
max number of bytes on queue is 16384
pid of last msgsnd is 2510
pid of last msgrcv is 0
last msgsnd time is Sun Dec 29 18:28:21 2002
last msgrcv time is Thu Jan  1 08:00:00 1970
last change time is Sun Dec 29 18:28:20 2002
msg uid is 0
msg gid is 0
read from msg queue 1 bytes
//实际d的字节数
current number of bytes on queue is 0
number of messages in queue is 0
max number of bytes on queue is 16384   //每个消息队列最大容量(字节敎ͼ
pid of last msgsnd is 2510
pid of last msgrcv is 2510
last msgsnd time is Sun Dec 29 18:28:21 2002
last msgrcv time is Sun Dec 29 18:28:22 2002
last change time is Sun Dec 29 18:28:20 2002
msg uid is 0
msg gid is 0
current number of bytes on queue is 0
number of messages in queue is 0
max number of bytes on queue is 16388   //可看U用户可修改消息队列最大容?
pid of last msgsnd is 2510
pid of last msgrcv is 2510  //Ҏ作消息队列进E的跟踪
last msgsnd time is Sun Dec 29 18:28:21 2002
last msgrcv time is Sun Dec 29 18:28:22 2002
last change time is Sun Dec 29 18:28:23 2002    //msgctl()调用对msg_ctime有媄?
msg uid is 8
msg gid is 8



参考资?

  • UNIX|络~程W二Pq程间通信Q作者:W.Richard StevensQ译者:杨张,清华大学出版C。对POSIX以及pȝV消息队列都有阐述Q对Linux环境下的E序开发有极大的启发意义?br />
  • linux内核源代码情景分析(上)Q毛h、胡希明著,江大学出版C,l出了系lV消息队列相关的源代码分析?br />
  • http://www.fanqiang.com/a4/b2/20010508/113315.htmlQ主要阐qlinux下对文g的操作,详细介绍了对文g的存取权限位Q对IPC对象的存取权限同样具有很好的借鉴意义?

  • msgget、msgsnd、msgrcv、msgctl手册


关于作?/span>

郑R_P现攻d防科大计机学院|络方向博士学位。您可以通过电子邮g mlinux@163.com和他联系?



true 2007-03-27 16:26 发表评论
]]>ldconfig几个需要注意的地方 zhuanhttp://www.shnenglu.com/true/archive/2007/03/27/20667.htmltruetrueTue, 27 Mar 2007 00:53:00 GMThttp://www.shnenglu.com/true/archive/2007/03/27/20667.htmlhttp://www.shnenglu.com/true/comments/20667.htmlhttp://www.shnenglu.com/true/archive/2007/03/27/20667.html#Feedback4http://www.shnenglu.com/true/comments/commentRss/20667.htmlhttp://www.shnenglu.com/true/services/trackbacks/20667.htmlldconfig几个需要注意的地方

1. 往/lib?usr/lib里面加东西,是不用修?etc/ld.so.conf的,但是完了之后要调一下ldconfigQ不然这个library会找不到
2. 惛_上面两个目录以外加东西的时候,一定要修改/etc/ld.so.confQ然后再调用ldconfigQ不然也会找不到
比如安装了一个mysql?usr/local/mysqlQmysql有一大堆library?usr/local/mysql/lib下面Q这时就需要在/etc/ld.so.conf下面加一?usr/local/mysql/libQ保存过后ldconfig一下,新的library才能在程序运行时被找到?/div>
3. 如果惛_q两个目录以外放libQ但是又不想?etc/ld.so.conf中加东西Q或者是没有权限加东西)。那也可以,是export一个全局变量LD_LIBRARY_PATHQ然后运行程序的时候就会去q个目录中找library。一般来讲这只是一U时的解决ҎQ在没有权限或旉要的时候用?/div>
4. ldconfig做的q些东西都与q行E序时有养I跟编译时一点关p都没有。编译的时候还是该?L得加,不要h了?/div>
5. MQ就是不做了什么关于library的变动后Q最好都ldconfig一下,不然会出C些意想不到的l果。不会花太多的时_但是会省很多的事?/div>


true 2007-03-27 08:53 发表评论
]]> re99þ6Ʒ| þþƷѲ| þƵվ| þٸ۲AV| avɫۺϾþavɫۺ| þùƷ99Ʒ987| ŷ˾þþƷ| þԭƷ| ĻƷþþþþ3Dն | Ʒ91þþþþþ| ŷɫۺϾþþþþ| ŷ˾þƬ| ˼˼þþƷ| ƷۺרƬþþ| ɫۺϾþ | ɫۺϾþþþۺ99| Ʒþþþþþ| ɫۺϾþ| ŷþþҹһĻ | ŷvaþþþ| þԾƷ| ƷþþþĻһ| þҹӰ| þ99Ʒþþþþhb| ߾þþƷĹ| þþƷƷ| AƷһþ| ˾þAV| ҰAVþһ| һŮȫƾþƬ| þþƷŷպ| ݺۺϾþۺ88 | ˾þô߽avӰԺ | þ91ƷۺϹҳ| ˬˬƬaþ| avþþþòվ| þþƷ99Ʒ| þۺϾƷþ| 2021Ʒҹþ| AþþƷ| ձþþþĻ|