准备知识:
1、了解THREADED(多线程)下c client运行的架构:
在多线程下,用户每次调用zookeeper_init生成一个zhandle_t结构都会生成除了调用线程外的另两线程:do_io线程和do_completion线程。
- do_completion:
主要内容是执行异步完成回调函数和watcher事件通知函数,代码比较简单,主要处理zk->completions_to_process队列。
#ifdef WIN32 |
unsigned __stdcall do_completion( void * v) |
#else |
void *do_completion(void *v) |
#endif |
{ |
zhandle_t *zh = v; |
api_prolog(zh); |
notify_thread_ready(zh); |
LOG_DEBUG(LOGCALLBACK(zh), "started completion thread"); |
while(!zh->close_requested) { |
pthread_mutex_lock(&zh->completions_to_process.lock); |
while(!zh->completions_to_process.head && !zh->close_requested) { |
pthread_cond_wait(&zh->completions_to_process.cond, &zh->completions_to_process.lock); |
} |
pthread_mutex_unlock(&zh->completions_to_process.lock); |
process_completions(zh); |
} |
api_epilog(zh, 0); |
LOG_DEBUG(LOGCALLBACK(zh), "completion thread terminated"); |
return 0; |
} |
- do_io:
该线程是核心线程,主要通过poll来异步处理与zookeeper server之间的通信。核心架构如下:
void *do_io(void *v) |
|
{ |
zhandle_t *zh = (zhandle_t*)v; |
|
struct pollfd fds[2]; |
struct adaptor_threads *adaptor_threads = zh->adaptor_priv; |
api_prolog(zh); |
notify_thread_ready(zh); |
LOG_DEBUG(LOGCALLBACK(zh), "started IO thread"); |
fds[0].fd=adaptor_threads->self_pipe[0]; // 在poll中注册self_pipe[0],用于激活或通知do_io线程。 |
fds[0].events=POLLIN; |
while(!zh->close_requested)
{
//while循环,直到调用zookeeper_close,使close_requested为真。
|
zh->io_count++; |
struct timeval tv; |
int fd; |
int interest; |
int timeout; |
int maxfd=1; |
int rc; |
zookeeper_interest(zh, &fd, &interest, &tv); //zookeeper_interest,判断zh->fd是否为-1(连接到server的socket fd)。 如果为-1,选择当前connect_index,对应的server进行连接。connect_index的修改是在handler_error里面搞的,round-robin。具体请参考:http://hi.baidu.com/anatacollin/item/fc9ccfb4dcedb8f363388e11 |
if (fd != -
1)
{
|
fds[1].fd=fd; |
fds[1].events=(interest&ZOOKEEPER_READ)?POLLIN:0; |
fds[1].events|=(interest&ZOOKEEPER_WRITE)?POLLOUT:0; |
maxfd=2; |
} |
timeout=tv.tv_sec * 1000 + (tv.tv_usec/1000); |
poll(fds,maxfd,timeout); |
if (fd != -1) { |
interest=(fds[1 |