0%

janus的线程模型

我们要想把一个系统搞清楚,首先要把它的线程模型弄明白。比如它是单线程的还是多线程的?如果它是单线程的,那逻辑就比较简单了,像mediasoup就是单进程多实例的模型;如果是多线程的,那它的线程是如何分配的?每个线程的作用是什么?我们必须把这些都要弄清楚才行,否则我们就无法将这个系统彻底搞明白。

在分析 janus 的时候,我们也应尊循上面的原则。因此在分析janus之前,我们先来问几个问题,janus是多线程的模式吗?如果是多线程模式,那它一共有几个线程呢? 这些线程又分别起什么作用?

如果我们将上面的问题回答好了,我想我们基本上就将janus的线程模型搞清楚了,搞清了它的线程模型也就撑握了janus的系统大体脉络。

janus是多线程模式吗?

其实这个问题非常好回答,通过查看janus的主文件janus.c我们就能知道答案了。在janus.c中我们可以发现下面的代码:

1
2
3
4
5
...
GThread *watchdog = g_thread_try_new("timeout watchdog", &janus_sessions_watchdog, watchdog_loop, &error);
...
GThread *requests_thread = g_thread_try_new("sessions requests", &janus_transport_requests, NULL, &error);
...

janus是基于Linux 的GLIB库开发出来的,因此所有对系统的调用都是使用的GLIB库的API。而g_thread_try_new函数正中GLIB中用来创建线程的,在g_thread_try_new的底层真正调用的是pthread的相关API。

通这上面的分析,我们可以知道janus是多线程的模式。

janus一共有几个线程?

除了我们上面介绍的两个线程外,janus还使用了线程池的概念。在janus的初始化阶段就将线程池创建出来了。代码如下:

1
2
3
...
tasks = g_thread_pool_new(janus_transport_task, NULL, -1, FALSE, &error);
...

查看g_thread_pool_newAPI的帮助文档,其定义如下:

1
2
3
4
5
6
GThreadPool *
g_thread_pool_new (GFunc func,
gpointer user_data,
gint max_threads,
gboolean exclusive,
GError **error);

通过这个定义我们可以知道janus创建的线程池时并没有对线程数进制控制。也就是说它可以开出系统可以支持的最大限度的线程个数。会在高并发时出现性能问题呢?这个还要等我们后面的深入分析才能清楚,目前来说这行代码还是有风险的。

下面我们总结一下,通过对janus.c文件的分析,我们现在可以知道janus的线程模型是由两个专用线程watchdogrequest和一个通用任务线程池构成的。如下图所示:

janus线程模型

了解了janus的线程模型后,下面我们来看一下 janus 每个线程的作用吧。

每个线程的作用

通过阅读代码,我们可以了解到这几个线程的主要作用是什么,下面我们来一一介绍一下。

首先是主线程,这个线程的主要作用就是初始化的工作。主要包括以下几方面的工作:

  • 从配置文件中读配置信息,然后根据配置信息进行初始化工作
  • 启动其它线程
  • 动态加载plugin

WatchDog 线程,通过名子我们基本上就可以清楚它的作用了。它是监控线程,它每隔2秒做一次扫描,查看transport的session是否过期了。如果过期了,则给对应的transport发通知让transport结束处理。需要注意的是,这里的 trasnport代表的是不同协议的接入口,如RabbitMQ、MQTT、HTTP等。

Request线程,用于处理接口请求。一般将接口请求分为两大类,文本类请求和命令类请求。如果是文本类请求的,则会启动新线程(从线程池中获取)进行处理;如果是命令的类的,则可以直接处理。当然对于命令类型的Request可能处理上会比较复杂,有可能会分成多个阶段处理,而在每个不同的阶段又会生成新的Request。

最后一个就是线程池了,线程池的作用上面我已经介绍了,就是在处理Request时会从线程池中分配线程,然后执行Request任务,任务完成后再回收到线程池里。  

小结

通过上面的描述我们可以看到janus的线程模型并不复杂,它启动了两个专门的线程,一个用于处理transport的session是否过期;另一个用于处理Request请求,当收到Request请求后,它又会把请求交给新的线程做延时处理。

以上我们就将 janus 的线程模型分析完了,读到这里我相信你已经对janus的线程模型有了一个大体的了解了。当然你仍然会很许多疑惑,这只能对照着janus的代码分析才能让你体会的更深刻!

谢谢!

参考

欢迎关注我的其它发布渠道