专门为难C高手,进程莫名其妙之退出

时间:2022-09-20 10:42:45
开发平台 solaris 10
工具gcc 3.4.6

我写一个套接字通讯程序,主进程死循环监听accept,若连接成功便产生处理线程。线程为detach方式。
程序运行几天便莫名奇妙之退出,并不产生core文件。
请问这里的高手门,
   使进程退出的一般原因是?
   最有效的线程调试方式是?
个别线程非法退出能导致主线程退出吗?
  unix下有经典跟踪、查看、调试线程的方法吗?

 期待真正的高手中。。。

30 个解决方案

#1


up

#2


和C一点关系没有。你的代码有BUG,需要调试。你有做过压力测试么?

#3


up

#4


打log看吧。

#5


linux下dbg unix下不太清楚

程序退出的话 不一定是线程造成的

#6


我以前也遇到过类似问题,原因还是自己程序有BUG,偶是写日志文件调试解决的

#7


线程间通信没处理好

#8


查看日志,打印出来才能发现问题吧

#9


Solaris 平台下有专门的C/C++调试工具: CodeView

最有效的线程调试方式是: 

    (1)采用“生产者-消费者”模型。
    (2)监听线程一个,只负责Socket监听,连接请求送至连接队列等待
    (3)任务调度线程一个,服务线程池中10~20个左右的服务线程
    (4)任务调度线程检查连接队列,如有连接请求,则检查服务线程池中有无空闲线程,
         如有,则分配任务。
    (5)服务线程任务完成后,不要销毁,直接进入空闲状态,等待调度线程分配下一个任务。

  注意:每连接一线程的方式,实现虽然简单,但如果连接太多,则极有可能引发系统抖动。

#10


引用 2 楼 jiangsheng 的回复:
和C一点关系没有。你的代码有BUG,需要调试。你有做过压力测试么?


用c写的程序,就当是和c有关系嘛
代码有bug,谁能保证自己的代码没bug,现在的问题是要找出这个bug
压力测试未做过,不好意思,高手。

#11


引用 4 楼 intuition444 的回复:
打log看吧。

log打了一堆,线程中很乱,同时10个线程中止,每个线程结束的位置不同,根本无法判断那里是错误终结点
现在需要一种有效的调试方法

#12


引用 7 楼 once_and_again 的回复:
线程间通信没处理好

我的程序,各个线程都是分离的,他们之间不进行通信
只是对全局变量的一个计数器thread_counter 进行加锁计数加减
每个线程中都有如下代码:
                        pthread_mutex_lock(&My_thread_locker);
                        My_thread_number_counter++;
                        pthread_mutex_unlock(&My_thread_locker);

奇怪的是今天产生core文件,gdb 居然发现pthread_mutex_unlock会产生线程不安全??
难道pthread_mutex_unlock是线程不安全函数???
#0  0x00024280 in pthread_mutex_unlock@plt () from /usr/lib/ld.so.1
(gdb) 
(gdb) where 
#0  0x00024280 in pthread_mutex_unlock@plt () from /usr/lib/ld.so.1
#1  0x00011624 in main (argc=148480, argv=0xffbffcc4) at MyHttpThread.c:118
(gdb) 

#13


顶起~~~

#14


程序运行几天便莫名奇妙之退出,并不产生core文件。 
============

难道你OS把你的程序杀死了, 连个core都没有。

难道内存越界访问? 或其它导致OS向你发KILL信号。
kill信号或sigsegv)我记得是不会有core记录的(好久没有做应用了), 只有你自己写handle抓, 
抓到的时候写到自己的log里面。
一种可能建议了, 不是高手。



#15


引用 14 楼 Arthur_ 的回复:
程序运行几天便莫名奇妙之退出,并不产生core文件。 
============ 

难道你OS把你的程序杀死了, 连个core都没有。 

难道内存越界访问? 或其它导致OS向你发KILL信号。 
kill信号或sigsegv)我记得是不会有core记录的(好久没有做应用了), 只有你自己写handle抓, 
抓到的时候写到自己的log里面。 
一种可能建议了, 不是高手。 


如果是内存越界,按照solaris的一贯做法肯定会生成core
而我的程序退出,没有任何错误提示,我想可能是某种信号导致程序退出,就像kill -9 pid
但是找不到这个信号的来源

#16


引用 9 楼 zming 的回复:
Solaris 平台下有专门的C/C++调试工具: CodeView 

最有效的线程调试方式是: 

    (1)采用“生产者-消费者”模型。 
    (2)监听线程一个,只负责Socket监听,连接请求送至连接队列等待 
    (3)任务调度线程一个,服务线程池中10~20个左右的服务线程 
    (4)任务调度线程检查连接队列,如有连接请求,则检查服务线程池中有无空闲线程, 
        如有,则分配任务。 
    (5)服务线程任务完成后,不要销…


你说的是程序结构设计问题吧,我现在面临的是如何调错问题,调试方法?

#17


引用 15 楼 jamesontan 的回复:
引用 14 楼 Arthur_ 的回复:
程序运行几天便莫名奇妙之退出,并不产生core文件。 
============ 

难道你OS把你的程序杀死了, 连个core都没有。 

难道内存越界访问? 或其它导致OS向你发KILL信号。 
kill信号或sigsegv)我记得是不会有core记录的(好久没有做应用了), 只有你自己写handle抓, 
抓到的时候写到自己的log里面。 
一种可能建议了, 不是高手。 
 

如果是内存越界,按照solaris的一贯做法肯定会生成c…


1。如果是kill,你可以在程序里面自己抓这个信号的。在这个信号的回调函数里面, 你把你的关键变量打印出来。
2。调试的时候你让你的程序在gdb下跑的吗?如果程序死了gdb也退出来了吗?如果没有可以(gdb) bt 下, 看看栈的情况。
多线程gdb调试确实比较烦。

#18


引用 16 楼 jamesontan 的回复:
引用 9 楼 zming 的回复:
Solaris 平台下有专门的C/C++调试工具: CodeView 

最有效的线程调试方式是: 

    (1)采用“生产者-消费者”模型。 
    (2)监听线程一个,只负责Socket监听,连接请求送至连接队列等待 
    (3)任务调度线程一个,服务线程池中10~20个左右的服务线程 
    (4)任务调度线程检查连接队列,如有连接请求,则检查服务线程池中有无空闲线程, 
        如有,则分配任务。 
    (5)…


线程调试以前也搞过,总结起来还得靠自己解决,经验最重要。

调试命令就那么几条, 推荐一篇帖子 线程方面的:
http://blog.chinaunix.net/u/11240/showart.php?id=340632

#19


引用 17 楼 Arthur_ 的回复:
引用 15 楼 jamesontan 的回复:
引用 14 楼 Arthur_ 的回复: 
程序运行几天便莫名奇妙之退出,并不产生core文件。 
============ 

难道你OS把你的程序杀死了, 连个core都没有。 

难道内存越界访问? 或其它导致OS向你发KILL信号。 
kill信号或sigsegv)我记得是不会有core记录的(好久没有做应用了), 只有你自己写handle抓, 
抓到的时候写到自己的log里面。 
一种可能建议了, 不是高手。 


如果是内存越界,按…


是的,如果使用gdb 程序名 启动程序,gdb也会退出,并生成core文件
Core was generated by `/tools/test/c/MyServerSrc/libsrc/mysrc/MyHttpThread'.
Program terminated with signal 5, Trace/breakpoint trap.
#0  0xff3c4500 in rtld_db_dlactivity () from /lib/ld.so.1
(gdb) where
#0  0xff3c4500 in rtld_db_dlactivity () from /lib/ld.so.1
#1  0xff3c46c8 in rd_event () from /lib/ld.so.1
#2  0xff3c59f0 in lm_move () from /lib/ld.so.1
#3  0xff3b8dbc in relocate_lmc () from /lib/ld.so.1
#4  0xff3ca51c in dlmopen_core () from /lib/ld.so.1
#5  0xff3ca6b0 in dlmopen_intn () from /lib/ld.so.1
#6  0xff3ca870 in dlmopen_check () from /lib/ld.so.1
#7  0xff3ca8b0 in dlopen () from /lib/ld.so.1
#8  0xff161244 in SO_per_src_lookup () from /lib/libc.so.1
#9  0xff15d0f0 in nss_get_backend_u () from /lib/libc.so.1
#10 0xff15dba8 in nss_search () from /lib/libc.so.1
#11 0xff227db0 in _switch_gethostbyname_r () from /lib/libnsl.so.1
#12 0xff226a98 in _get_hostserv_inetnetdir_byname () from /lib/libnsl.so.1
#13 0xff2232e8 in gethostbyname_r () from /lib/libnsl.so.1
#14 0x00011d6c in MyHttpConnect ()
#15 0x00010f00 in MyHTTP_thread (LocalSock=0x45) at MyHttpThreadProxy.c:18
#16 0xff1c5800 in _lwp_start () from /lib/libc.so.1
#17 0xff1c5800 in _lwp_start () from /lib/libc.so.1
Backtrace stopped: previous frame identical to this frame (corrupt stack?)
(gdb) 

gdb对于单进程调试确实不错,但是对于线程实在是不敢。。。。

#20


引用 18 楼 Arthur_ 的回复:
引用 16 楼 jamesontan 的回复:
引用 9 楼 zming 的回复: 
Solaris 平台下有专门的C/C++调试工具: CodeView 

最有效的线程调试方式是: 

    (1)采用“生产者-消费者”模型。 
    (2)监听线程一个,只负责Socket监听,连接请求送至连接队列等待 
    (3)任务调度线程一个,服务线程池中10~20个左右的服务线程 
    (4)任务调度线程检查连接队列,如有连接请求,则检查服务线程池中有无空闲线程, 
      …


现在gcc编译的时候不加-g还好,一加就经常产生core文件
去掉gdb跟踪之后,发现程序每次最后退出的线程有个提示 broken pipe 
经过查证,在网上搜索了一番,别人解释原因是向已经关闭连接的SOCKET管道写入数据造成的
。UNIX的系统是采用信号机制向进程通知这种系统错误的,13 SIGPIPE 的默认操作是Exit,从而造成主进程不告而别,现在请教高手们如何处理该信号?

#21


这个似乎比较容易解决,
你send 的时候后对段已经close了, 这时候内核异常向应用程序产生一个SIGPIPE信号, 你把这个信号在程序里面获得,然后在处理这个信号返回0就好了。
程序默认对这个信号的处理就是退出, 向自己发kill信号。


#22


在程序初始化的时候加上:
signal(SIGPIPE, handler)

然后void handle(int sig)
{
return ;
}

#23


或者在开头加上:struct   sigaction   sa;  sa.sa_handler   =   SIG_IGN;  sigaction(   SIGPIPE,   &sa,   0   );  

或者
signal(SIGPIPE,SIG_IGN);

#24


up

#25


还是不怎么懂。

#26


感谢Arthur_ ,看的出你的编程经验很丰富。

#27


引用 10 楼 jamesontan 的回复:
引用 2 楼 jiangsheng 的回复:
和C一点关系没有。你的代码有BUG,需要调试。你有做过压力测试么? 
用c写的程序,就当是和c有关系嘛 
代码有bug,谁能保证自己的代码没bug,现在的问题是要找出这个bug 
压力测试未做过,不好意思,高手。

就算有人把C语言标准背得滚瓜烂熟,不看你的代码也不可能解决你的问题。你要找调试BUG的高手的话,叫C高手来是浪费你自己和大家的时间。举个例子,你得了癌症,会去找传染病科名医诊治么?

#28


引用 27 楼 jiangsheng 的回复:
引用 10 楼 jamesontan 的回复:
引用 2 楼 jiangsheng 的回复: 
和C一点关系没有。你的代码有BUG,需要调试。你有做过压力测试么? 
用c写的程序,就当是和c有关系嘛 
代码有bug,谁能保证自己的代码没bug,现在的问题是要找出这个bug 
压力测试未做过,不好意思,高手。 
 
就算有人把C语言标准背得滚瓜烂熟,不看你的代码也不可能解决你的问题。你要找调试BUG的高手的话,叫C高手来是浪费你自己和大家的时间。举个例子,你…

Arthur_ 没有看我的代码,不晓得他是不是传染病科名医诊治么?至少他提供了一套有效的建议和看法,而不是在这里空谈医学理论。

#29


我的意思是你发错区了
你的问题是 
unix下有经典跟踪、查看、调试线程的方法吗? 
却发在了C语言区,指明C语言的帮助,你是在浪费大部分看贴的人的时间。
你不在乎浪费别人时间,但是别人在乎。
引用《提问的智慧》(http://community.csdn.net/IndexPage/SmartQuestion.aspx#forum)
弄清楚你的主题!最典型的错误之一是在某种致立于跨Unix和Windows平台的语言、库或工具的论坛中提关于操作系统程序接口的问题。如果你不明白为什么这是大错,最好在搞清楚概念前什么也别问。

#30


jiangsheng的功底很深,你应该多多听听他的,高手.

#1


up

#2


和C一点关系没有。你的代码有BUG,需要调试。你有做过压力测试么?

#3


up

#4


打log看吧。

#5


linux下dbg unix下不太清楚

程序退出的话 不一定是线程造成的

#6


我以前也遇到过类似问题,原因还是自己程序有BUG,偶是写日志文件调试解决的

#7


线程间通信没处理好

#8


查看日志,打印出来才能发现问题吧

#9


Solaris 平台下有专门的C/C++调试工具: CodeView

最有效的线程调试方式是: 

    (1)采用“生产者-消费者”模型。
    (2)监听线程一个,只负责Socket监听,连接请求送至连接队列等待
    (3)任务调度线程一个,服务线程池中10~20个左右的服务线程
    (4)任务调度线程检查连接队列,如有连接请求,则检查服务线程池中有无空闲线程,
         如有,则分配任务。
    (5)服务线程任务完成后,不要销毁,直接进入空闲状态,等待调度线程分配下一个任务。

  注意:每连接一线程的方式,实现虽然简单,但如果连接太多,则极有可能引发系统抖动。

#10


引用 2 楼 jiangsheng 的回复:
和C一点关系没有。你的代码有BUG,需要调试。你有做过压力测试么?


用c写的程序,就当是和c有关系嘛
代码有bug,谁能保证自己的代码没bug,现在的问题是要找出这个bug
压力测试未做过,不好意思,高手。

#11


引用 4 楼 intuition444 的回复:
打log看吧。

log打了一堆,线程中很乱,同时10个线程中止,每个线程结束的位置不同,根本无法判断那里是错误终结点
现在需要一种有效的调试方法

#12


引用 7 楼 once_and_again 的回复:
线程间通信没处理好

我的程序,各个线程都是分离的,他们之间不进行通信
只是对全局变量的一个计数器thread_counter 进行加锁计数加减
每个线程中都有如下代码:
                        pthread_mutex_lock(&My_thread_locker);
                        My_thread_number_counter++;
                        pthread_mutex_unlock(&My_thread_locker);

奇怪的是今天产生core文件,gdb 居然发现pthread_mutex_unlock会产生线程不安全??
难道pthread_mutex_unlock是线程不安全函数???
#0  0x00024280 in pthread_mutex_unlock@plt () from /usr/lib/ld.so.1
(gdb) 
(gdb) where 
#0  0x00024280 in pthread_mutex_unlock@plt () from /usr/lib/ld.so.1
#1  0x00011624 in main (argc=148480, argv=0xffbffcc4) at MyHttpThread.c:118
(gdb) 

#13


顶起~~~

#14


程序运行几天便莫名奇妙之退出,并不产生core文件。 
============

难道你OS把你的程序杀死了, 连个core都没有。

难道内存越界访问? 或其它导致OS向你发KILL信号。
kill信号或sigsegv)我记得是不会有core记录的(好久没有做应用了), 只有你自己写handle抓, 
抓到的时候写到自己的log里面。
一种可能建议了, 不是高手。



#15


引用 14 楼 Arthur_ 的回复:
程序运行几天便莫名奇妙之退出,并不产生core文件。 
============ 

难道你OS把你的程序杀死了, 连个core都没有。 

难道内存越界访问? 或其它导致OS向你发KILL信号。 
kill信号或sigsegv)我记得是不会有core记录的(好久没有做应用了), 只有你自己写handle抓, 
抓到的时候写到自己的log里面。 
一种可能建议了, 不是高手。 


如果是内存越界,按照solaris的一贯做法肯定会生成core
而我的程序退出,没有任何错误提示,我想可能是某种信号导致程序退出,就像kill -9 pid
但是找不到这个信号的来源

#16


引用 9 楼 zming 的回复:
Solaris 平台下有专门的C/C++调试工具: CodeView 

最有效的线程调试方式是: 

    (1)采用“生产者-消费者”模型。 
    (2)监听线程一个,只负责Socket监听,连接请求送至连接队列等待 
    (3)任务调度线程一个,服务线程池中10~20个左右的服务线程 
    (4)任务调度线程检查连接队列,如有连接请求,则检查服务线程池中有无空闲线程, 
        如有,则分配任务。 
    (5)服务线程任务完成后,不要销…


你说的是程序结构设计问题吧,我现在面临的是如何调错问题,调试方法?

#17


引用 15 楼 jamesontan 的回复:
引用 14 楼 Arthur_ 的回复:
程序运行几天便莫名奇妙之退出,并不产生core文件。 
============ 

难道你OS把你的程序杀死了, 连个core都没有。 

难道内存越界访问? 或其它导致OS向你发KILL信号。 
kill信号或sigsegv)我记得是不会有core记录的(好久没有做应用了), 只有你自己写handle抓, 
抓到的时候写到自己的log里面。 
一种可能建议了, 不是高手。 
 

如果是内存越界,按照solaris的一贯做法肯定会生成c…


1。如果是kill,你可以在程序里面自己抓这个信号的。在这个信号的回调函数里面, 你把你的关键变量打印出来。
2。调试的时候你让你的程序在gdb下跑的吗?如果程序死了gdb也退出来了吗?如果没有可以(gdb) bt 下, 看看栈的情况。
多线程gdb调试确实比较烦。

#18


引用 16 楼 jamesontan 的回复:
引用 9 楼 zming 的回复:
Solaris 平台下有专门的C/C++调试工具: CodeView 

最有效的线程调试方式是: 

    (1)采用“生产者-消费者”模型。 
    (2)监听线程一个,只负责Socket监听,连接请求送至连接队列等待 
    (3)任务调度线程一个,服务线程池中10~20个左右的服务线程 
    (4)任务调度线程检查连接队列,如有连接请求,则检查服务线程池中有无空闲线程, 
        如有,则分配任务。 
    (5)…


线程调试以前也搞过,总结起来还得靠自己解决,经验最重要。

调试命令就那么几条, 推荐一篇帖子 线程方面的:
http://blog.chinaunix.net/u/11240/showart.php?id=340632

#19


引用 17 楼 Arthur_ 的回复:
引用 15 楼 jamesontan 的回复:
引用 14 楼 Arthur_ 的回复: 
程序运行几天便莫名奇妙之退出,并不产生core文件。 
============ 

难道你OS把你的程序杀死了, 连个core都没有。 

难道内存越界访问? 或其它导致OS向你发KILL信号。 
kill信号或sigsegv)我记得是不会有core记录的(好久没有做应用了), 只有你自己写handle抓, 
抓到的时候写到自己的log里面。 
一种可能建议了, 不是高手。 


如果是内存越界,按…


是的,如果使用gdb 程序名 启动程序,gdb也会退出,并生成core文件
Core was generated by `/tools/test/c/MyServerSrc/libsrc/mysrc/MyHttpThread'.
Program terminated with signal 5, Trace/breakpoint trap.
#0  0xff3c4500 in rtld_db_dlactivity () from /lib/ld.so.1
(gdb) where
#0  0xff3c4500 in rtld_db_dlactivity () from /lib/ld.so.1
#1  0xff3c46c8 in rd_event () from /lib/ld.so.1
#2  0xff3c59f0 in lm_move () from /lib/ld.so.1
#3  0xff3b8dbc in relocate_lmc () from /lib/ld.so.1
#4  0xff3ca51c in dlmopen_core () from /lib/ld.so.1
#5  0xff3ca6b0 in dlmopen_intn () from /lib/ld.so.1
#6  0xff3ca870 in dlmopen_check () from /lib/ld.so.1
#7  0xff3ca8b0 in dlopen () from /lib/ld.so.1
#8  0xff161244 in SO_per_src_lookup () from /lib/libc.so.1
#9  0xff15d0f0 in nss_get_backend_u () from /lib/libc.so.1
#10 0xff15dba8 in nss_search () from /lib/libc.so.1
#11 0xff227db0 in _switch_gethostbyname_r () from /lib/libnsl.so.1
#12 0xff226a98 in _get_hostserv_inetnetdir_byname () from /lib/libnsl.so.1
#13 0xff2232e8 in gethostbyname_r () from /lib/libnsl.so.1
#14 0x00011d6c in MyHttpConnect ()
#15 0x00010f00 in MyHTTP_thread (LocalSock=0x45) at MyHttpThreadProxy.c:18
#16 0xff1c5800 in _lwp_start () from /lib/libc.so.1
#17 0xff1c5800 in _lwp_start () from /lib/libc.so.1
Backtrace stopped: previous frame identical to this frame (corrupt stack?)
(gdb) 

gdb对于单进程调试确实不错,但是对于线程实在是不敢。。。。

#20


引用 18 楼 Arthur_ 的回复:
引用 16 楼 jamesontan 的回复:
引用 9 楼 zming 的回复: 
Solaris 平台下有专门的C/C++调试工具: CodeView 

最有效的线程调试方式是: 

    (1)采用“生产者-消费者”模型。 
    (2)监听线程一个,只负责Socket监听,连接请求送至连接队列等待 
    (3)任务调度线程一个,服务线程池中10~20个左右的服务线程 
    (4)任务调度线程检查连接队列,如有连接请求,则检查服务线程池中有无空闲线程, 
      …


现在gcc编译的时候不加-g还好,一加就经常产生core文件
去掉gdb跟踪之后,发现程序每次最后退出的线程有个提示 broken pipe 
经过查证,在网上搜索了一番,别人解释原因是向已经关闭连接的SOCKET管道写入数据造成的
。UNIX的系统是采用信号机制向进程通知这种系统错误的,13 SIGPIPE 的默认操作是Exit,从而造成主进程不告而别,现在请教高手们如何处理该信号?

#21


这个似乎比较容易解决,
你send 的时候后对段已经close了, 这时候内核异常向应用程序产生一个SIGPIPE信号, 你把这个信号在程序里面获得,然后在处理这个信号返回0就好了。
程序默认对这个信号的处理就是退出, 向自己发kill信号。


#22


在程序初始化的时候加上:
signal(SIGPIPE, handler)

然后void handle(int sig)
{
return ;
}

#23


或者在开头加上:struct   sigaction   sa;  sa.sa_handler   =   SIG_IGN;  sigaction(   SIGPIPE,   &sa,   0   );  

或者
signal(SIGPIPE,SIG_IGN);

#24


up

#25


还是不怎么懂。

#26


感谢Arthur_ ,看的出你的编程经验很丰富。

#27


引用 10 楼 jamesontan 的回复:
引用 2 楼 jiangsheng 的回复:
和C一点关系没有。你的代码有BUG,需要调试。你有做过压力测试么? 
用c写的程序,就当是和c有关系嘛 
代码有bug,谁能保证自己的代码没bug,现在的问题是要找出这个bug 
压力测试未做过,不好意思,高手。

就算有人把C语言标准背得滚瓜烂熟,不看你的代码也不可能解决你的问题。你要找调试BUG的高手的话,叫C高手来是浪费你自己和大家的时间。举个例子,你得了癌症,会去找传染病科名医诊治么?

#28


引用 27 楼 jiangsheng 的回复:
引用 10 楼 jamesontan 的回复:
引用 2 楼 jiangsheng 的回复: 
和C一点关系没有。你的代码有BUG,需要调试。你有做过压力测试么? 
用c写的程序,就当是和c有关系嘛 
代码有bug,谁能保证自己的代码没bug,现在的问题是要找出这个bug 
压力测试未做过,不好意思,高手。 
 
就算有人把C语言标准背得滚瓜烂熟,不看你的代码也不可能解决你的问题。你要找调试BUG的高手的话,叫C高手来是浪费你自己和大家的时间。举个例子,你…

Arthur_ 没有看我的代码,不晓得他是不是传染病科名医诊治么?至少他提供了一套有效的建议和看法,而不是在这里空谈医学理论。

#29


我的意思是你发错区了
你的问题是 
unix下有经典跟踪、查看、调试线程的方法吗? 
却发在了C语言区,指明C语言的帮助,你是在浪费大部分看贴的人的时间。
你不在乎浪费别人时间,但是别人在乎。
引用《提问的智慧》(http://community.csdn.net/IndexPage/SmartQuestion.aspx#forum)
弄清楚你的主题!最典型的错误之一是在某种致立于跨Unix和Windows平台的语言、库或工具的论坛中提关于操作系统程序接口的问题。如果你不明白为什么这是大错,最好在搞清楚概念前什么也别问。

#30


jiangsheng的功底很深,你应该多多听听他的,高手.