接口线程安全隐患

    在很多第三方提供的接口中,有些会说明此接口是线程安全,正因为这样的说明,会导致很多没有经验的程序员出现莫名其妙的错误,笔者现在以libmemcached的 memcached_pool_release() 和 memcached_pool_fetch()为例进行简单的说明。

    在libmemcached的官方文档中,已经说明者两个函数是线程安全的,在使用的过程中可能会出现如下的使用情况:


typedef struct memcached_server_tag
{
	memcached_pool_st *memc_svr_pool;
}memcached_server_t;

memcached_server_t *create_memcached_server(const char *memc_server_config,size_t size)
{
    assert(memc_server_config);

    memcached_server_t *mem_svr = g_malloc(sizeof(memcached_server_t));
    if (NULL == mem_svr)
    {   
        DPRINT(1,NULL,"g_malloc failed \n"); 
        assert(mem_svr);
        return NULL;
    }   

    mem_svr->memc_svr_pool = memcached_pool(memc_server_config,size);

    if (NULL == mem_svr->memc_svr_pool)
    {   
        DPRINT(1,NULL,"create memcached server pool failed \n");
        assert(mem_svr->memc_svr_pool);
        g_free(mem_svr);
        return NULL;
    }

    return mem_svr;
}

void destroy_memcached_server(memcached_server_t *memc_server)
{
    if (memc_server)
    {
        memcached_pool_destroy(memc_server->memc_svr_pool);
        g_free(memc_server);
    }
}

static int memc_pool_release(memcached_server_t *memc_server,memcached_st *mem_s)
{
    memcached_return_t rt = memcached_pool_release(memc_server->memc_svr_pool,mem_s);
    if (MEMCACHED_SUCCESS != rt)
    {
        DPRINT(2,NULL,"memcached_pool_release. [%s]\n",memcached_strerror(mem_s,rt));
        return -1;
    }

    return 0;
}

char * memcached_server_get(memcached_server_t *memc_server,const char *key,size_t key_length,size_t *value_length)
{
    assert(memc_server);
    assert(memc_server->memc_svr_pool);
    assert(key);
    assert(value_length);

    memcached_return_t rt;
    memcached_st *mem_s = memcached_pool_fetch(memc_server->memc_svr_pool,NULL,&rt);
    if (memcached_failed(rt))
    {
        DPRINT(2,NULL,"memcached_pool_fetch failed. [%s]\n",memcached_strerror(mem_s,rt));
        return NULL;
    }

    char *value = NULL;
    uint32_t flag;
    value = memcached_get(mem_s,key,key_length,value_length,&flag,&rt);
    if (memcached_failed(rt))
    {
        DPRINT(6,NULL,"memcached_get failed. [key : %s, reason : %s]\n",key,memcached_strerror(mem_s,rt));
    }
    memc_pool_release(memc_server,mem_s);

    return value;   //remember: it must be free by caller
}

测试代码:

host = "127.0.0.1:11220";
memcached_server_t *memcached_server = create_memcached_server(host,strlen(host));

在多线程环境下执行:
thread1:
	memcached_server_get(memcached_server,key1,key1_size,&value_size);
	
thread2
	memcached_server_get(memcached_server,key2,key2_size,&value_size);

    以上的测试,有个线程获取关键字的值可能会失败。假如thread1正执行在69行代码处(memcached_get),而此时thread2也进入memcached_server_get函数,如果thread2在执行memcached_pool_fetch时,thread1还没有释放资源(memc_pool_release),thread2将会在memcached_pool_fetch处执行失败,从而导致整个程序的错误结果。

    因此在理解这些线程安全的接口上的时候,需要万分的注意。线程安全接口,使用的数据结构都是相互独立的,所以我们可以用相互独立的memcached_server_t结构指针,去代替全局的memcached_server。


你可能感兴趣的:(线程安全,libmemcached)