软件开发: 09 2009存档

       APC可以给php加速,但我在这里不是介绍APC的。
       项目开发中我们做了一个php module,里面用到了emalloc和efree,用http_load做了压力一切正常,但装了php-apc以后,httpd进程就一个劲的 core dump。后来查到原因是APC接管了emalloc和efree(具体怎么接管的没来得及查,导致emalloc/efree行为和以前不一致,最后崩 溃。
       对于php开发者,APC是透明的;对于php module开发者,APC可就要了命了,先别用emalloc/efree吧。
声明一个父类Parent,两个子类Son和Daughter继承之,分别将两个子类的创建和实现编译成动态链接库son.so, daughter.so,再通过动态库调用的hello方法:
/* parent.h */
class Parent
{
public:
    virtual void hello(void)=0;
    virtual void bye(void);
};



/* son.h */
#include "parent.h"

class Son : public Parent
{
    virtual void hello(void);
};

extern "C" static Parent* createPeople(void);


/* son.cpp */
#include <stdio.h>

#include "son.h"

void Son::hello(void)
{
    printf("son\n");
}

static Parent* createPeople(void)
{
    return new Son;
}



/* daughter.h */
#include "parent.h"

class Daughter : public Parent
{
    virtual void hello(void);
};

extern "C" static Parent* createPeople(void);



/* daughter.cpp */
#include <stdio.h>

#include "daughter.h"

void Daughter::hello(void)
{
    printf("daughter\n");
}

static Parent* createPeople(void)
{
    return new Daughter;
}


/* test.cpp */
#include <stdio.h>
#include <dlfcn.h>
#include "parent.h"

typedef Parent* (Func)(void);

int main(void)
{
    void* handle = dlopen("./daughter.so", RTLD_LAZY);

    if (handle)
    {
        Func* f = (Func*)dlsym(handle, "createPeople");
        if (f)
        {
            Parent* p = f();
            if (p)
            {
                p->hello();
            }
        }
        else
        {
            printf("dlsym:%s\n", dlerror());
        }
    }
    else
    {
        printf("dlopen:%s\n", dlerror());
    }
}

代码如上,现在编译链接:
 
g++ -shared son.cpp -o son.so -fPIC
g++ -shared daughter.cpp -o daughter.so -fPIC
g++ test.cpp -o test -ldl
 
运行test,报错:
 
dlopen:./daughter.so: undefined symbol: _ZTV6Parent
 
找不到符号Parent,那么nm daughter.so看看是不是没有Parent这个符号,结果看到:
.... 
                 U _ZTI6Parent
0000000000100f00 V _ZTI8Daughter
0000000000000ba0 V _ZTS8Daughter
                 U _ZTV6Parent
...
居然有两个Parent符号!其中_ZTV6Parent就是dlopen报找不到错误的那个。初遇这个错误让人头晕,哪里蹦出来两个 Parent?仔细检查最后才发现,Parent有两个虚函数,一个是纯虚函数,一个是普通的虚函数,编译器为这两个虚函数分别生成了两个入口表 _ZTI6Parent和_ZTV6Parent,所以最后链接错误。
改正的方法是干脆把两个虚函数都改为纯虚,当然,这只是很多修改方案中的一个。这里最重要的结论是g++对纯虚函数和虚函数会生成两个链接符号入口,知道这一点,再见到这种链接错误就能处理了。