在很多第三方提供的接口中,有些会说明此接口是线程安全,正因为这样的说明,会导致很多没有经验的程序员出现莫名其妙的错误,笔者现在以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。