ctx_t封装了与zeromq库相关的全部全局状态。当使用zeromq时,需要调用zmq_ctx_new函数创建一个ctx_t对象,并返回该对象,没有对context对象进行初始化。其中一个重要的变量starting,它为true时,表示context创建,但是未创建任何一个socket对象。
当创建地一个socket时,会先初始化context对象,来准备运行环境。
void *zmq_socket (void *ctx_, int type_)
{
if (!ctx_ || !((zmq::ctx_t *) ctx_)->check_tag ()) {
errno = EFAULT;
return NULL;
}
zmq::ctx_t *ctx = (zmq::ctx_t *) ctx_;
zmq::socket_base_t *s = ctx->create_socket (type_);
return (void *) s;
}
通过ctx_t中的create_socke函数创建socket:
zmq::socket_base_t *zmq::ctx_t::create_socket (int type_)
{
scoped_lock_t locker(slot_sync);
if (unlikely (starting)) {
starting = false;//确保context对象只会初始化一次
opt_sync.lock ();
int mazmq = max_sockets;//最大sockets数量
int ios = io_thread_count;//io线程数量
opt_sync.unlock ();
slot_count = mazmq + ios + 2;//槽的总数,sockets+io+term+reaper
slots = (i_mailbox **) malloc (sizeof (i_mailbox*) * slot_count);
alloc_assert (slots);
//初始化term线程的一些基础设施,用于销毁context时,执行一些清理工作
slots [term_tid] = &term_mailbox;
//创建reaper线程,并启动(还不清楚reaper线程的作用)
reaper = new (std::nothrow) reaper_t (this, reaper_tid);
alloc_assert (reaper);
slots [reaper_tid] = reaper->get_mailbox ();
reaper->start ();
//创建IO线程,并启动,可以启动多个IO线程
for (int i = 2; i != ios + 2; i++) {
io_thread_t *io_thread = new (std::nothrow) io_thread_t (this, i);
alloc_assert (io_thread);
io_threads.push_back (io_thread);
slots [i] = io_thread->get_mailbox ();
io_thread->start ();
}
//初始化未使用的socket槽索引
for (int32_t i = (int32_t) slot_count - 1;
i >= (int32_t) ios + 2; i--) {
empty_slots.push_back (i);
slots [i] = NULL;
}
}
//context已经处于销毁状态,则不能创建socket
if (terminating) {
errno = ETERM;
return NULL;
}
//socket已经达到最大数量,不能创建
if (empty_slots.empty ()) {
errno = EMFILE;
return NULL;
}
//为socket选择一个槽索引
uint32_t slot = empty_slots.back ();
empty_slots.pop_back ();
// Generate new unique socket ID.
int sid = ((int) max_socket_id.add (1)) + 1;
//创建socket,并注册mailbox
socket_base_t *s = socket_base_t::create (type_, this, slot, sid);
if (!s) {
empty_slots.push_back (slot);
return NULL;
}
sockets.push_back (s);
slots [slot] = s->get_mailbox ();
return s;
}