之前就有这样的疑惑,只是一直没有遇到过这个问题,也没有动手翻下代码去一探究竟,而最近在写SQL洞察组件时遇到了一点麻烦,今晚就来看一下,整个过程也非常的简单易懂。
直接拉到线程对象的初始化阶段, 函数调用过程如下:
::pfs_spawn_thread(void *)
::handle_connection(void *)
init_new_thd(Channel_info*)
THD::set_new_thread_id()
Global_THD_manager::get_new_thread_id()
每个线程的id都是通过thd_manager来进行分配的,逻辑实现在函数get_new_thread_id中,如下:
my_thread_id Global_THD_manager::get_new_thread_id()
{
my_thread_id new_id;
Mutex_lock lock(&LOCK_thread_ids);
do {
new_id= thread_id_counter++;
} while (!thread_ids.insert_unique(new_id).second);
return new_id;
}
解释下就是:在锁保护下获取全局的thread_id_counter,给当前线程并且自增,其中thread_id_counter的类型为unsigned int
,所以标题中的第一个问题已经有答案了,(99.99%)最大到2^32-1。随后需要去做插入操作,MySQL通过Thread_id_array来维护当前所有的线程,插入时会判断当前是否已经存在了此id
std::pair<iterator, bool> insert_unique(const value_type &val)
{
std::pair<iterator, iterator> p= std::equal_range(begin(), end(), val);
// p.first == p.second means we did not find it.
if (p.first == p.second)
return std::make_pair(insert(p.first, val), true);
return std::make_pair(p.first, false);
}
如果存在的话,继续递增。Thread_id_array的类型为MySQL自己实现的Prealloced_array,感兴趣可以阅读代码prealloced_array.h,里面有详细的使用说明。另外,当客户端连接关闭时,会调用函数release_thread_id,从thread_ids移除当前id号。
第二个问题,会用尽吗?假设当前已经自增到了最大值,再往后就是0,如果id为0的线程未释放,仍然被占用,则会继续递增,直到出现尚未被占用的id号,所以如果数据库中从0到2^32-1都已经被占用,会出现死循环(用尽了),但是我有理由相信你不会遇到这种情况。
调试跟踪过程:
结束。
文章转载自MySQLLabs,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。