pthread_create用法上的小问题

来源:互联网 发布:手机钢琴软件教学软件 编辑:程序博客网 时间:2024/05/18 04:30
天解决了困扰我好久的一个问题:短信网关内存不断攀升(好像看似内存泄露)。兴奋之余,积极响应ds和小飞鱼的号召,把此问题分享出来。虽然可供参考的部分并不多,但是也有一定的反面教材意义:-)

问题描述:
原有的短信网关,每产生一个socket连接,就会create一个或多个thread去处理这个socket上的数据收发(数据收发是在 CTCPConnection类中完成,这个类自动创建线程)。根据观察,每次有新连接时,内存都会固定增长20M,并且当连接断开(所有new出来的内存也被释放了)之后,内存并不使用并没有降低。表现为“内存泄露”的现象。
另一个奇怪的现象是:该问题只出现在四川现场,在家里做测试并无异常。


初步分析:
此问题看似内存泄露,但实际肯定不是。因为程序里并没有哪个地方申请了20M的内存,并且经过细致检查new和delete,初步排除了内存泄露的可能。知觉将问题所定在操作系统的软件配置和环境设置上。


试验结果:
为了进一步找出问题,书写了如下代码:
int main(int argc,char *argv[])
{
        int i=0;
        char *szP=NULL;
        while(true){
                i++;
                szP=new char[10240];
                delete []szP;
                sleep(5);
        }
}
运行测试发现内存随有攀升,但是能够降下来,说明环境本身的new和delete执行都是正常的。考虑到短信网关中,每次内存攀升都是伴随着新socket连接而产生,而新socket连接会引起新线程的创建。
故修改测试代码如下:
void *testthread(void *)
{
        printf("I am working./n");
        char *szP=NULL;
        szP=new char[10240];
        delete []szP;
        printf("I am stopping./n");
        pthread_exit(0);
}

int main(int argc,char *argv[])
{
        int i=0;
        pthread_t pid;
        char *szP=NULL;
        while(true){
                i++;
                pthread_create(&pid,NULL,testthread,&i);
                printf("ok%d,pid=%d/n",i,pid);
                sleep(5);
        }
}
运行测试发现,每次线程创建,都会使内存使用攀升10M(在短信网关中,一个新的socket连接会引起两个线程的创建,而每次内存攀升的量刚好是20M)。
看来问题已经非常明显,pthread_create存在问题。那么是环境问题还是使用方法上的问题呢?通过仔细阅读man手册,发现pthread一族函数中有一个叫做pthread_detach的函数,其作用是将资源控制所有权交给子线程(put a running thread in the detached state)。该函数应当由父线程调用。
以往我们写程序的时候,总是在pthread_create之后就万事大吉了,事实上无论是win下还是*nix下,创建线程都有很多细节问题需要注意。这里面有一点需要说明,并不是pthread_create必须和 pthread_detach结对出现,怎样使用pthread_detach和资源所有权的使用策略相关。一个简单的做法就是通过 pthread_detach将资源所有权交给被创建的线程,这样,一旦该线程退出,pthread_create为其所分配的资源将得到有效释放。


问题的解决:
简单的解决办法,在所有的pthread_create之后加入了thread_detach。捎带手,还把所有win下的CreateThread所返回的HANDLE给Close了(免得每次在任务管理器里看到我写的程序都使用了n多句柄)。至于在其他系统上并未出现此问题,可能确实和系统的环境配置有关,但是并不是说可以依赖环境配置去解决这个问题。因为问题的根本在于pthread_create的用法上。

事后的反思:
从解决问题的过程上看,此次对问题的解决并没有什么很复杂的过程。和小飞鱼不同的是,小飞鱼所采用的办法是一步步隔离问题,去掉无关项,将问题一步步简化。而我所采取的是将现实的问题一步步加入到测试环境中,使问题逐渐复杂化。前一种方法在较大的工程中非常有效,而后一种方法在问题的快速解决上有一定优势。两者的共同点就是:“矢志不渝的进行错误隔离,观察细节引起的差异”。
从问题产生的根源上看,这次的问题不能不说反映了我们开发过程、开发习惯的一些问题。由于项目紧张,我们可能会在一两天之内就学“一门”新技术,然后把它应用到工程中。可是我们这种“学习”往往为后面的工程带来了很多隐患。另外,对于我这次的问题来讲,我并不是因为没有时间去学,而是没有去学。主要是看问题只看到能够快速见效的一层,而不去关注那些深层次的问题。这其实是一种潜意识里的急功近利的思想在作祟。
原创粉丝点击