热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

WebRTC源代码探索之旅——多线程篇1

转自:http:blog.csdn.netkenny_zharticledetails38580919随着CPU频率接近物理极限,多芯片、多核几乎成为了

转自:http://blog.csdn.net/kenny_zh/article/details/38580919


随着CPU频率接近物理极限,多芯片、多核几乎成为了加速软件运行速度的唯一选择。与之相应地,多线程、异步编程以及并发编程成为了软件开发人员的必修课。因此,各种各样的开发框架不断涌现。在C++领域,boost的thread库等优秀的多线程框架也是其中的代表。特别是针对socket网络编程的boost.asio库可以轻松帮助开发人员实现多线程大量并发的网络服软件。

 

与这些框架相比,WebRTC的多线程模型还是比较特别的。它的核心是类似于WSAWaitForMultipleEvents的多路信号分离器。这是我最喜欢的多线程模型。它使每条线程既可以处理消息(post、send),同时也可以处理多个IO。并且在必要的情况下让一条线程独占(管理)一些资源,避免过多的使用锁造成线程死锁。个人认为这种模型可以帮助开发人员更容易地实现快速响应的界面程序。

 

WebRTC的线程模块放在/trunk/talk/base目录下,namespace使用talk_base::。主要涉及criticalsection、event、messagequeue、thread、messagehandler、physicalsocketserver等文件。顺便提一下,现在网上仅有的几篇关于WebRTC或是libjingle的文章多数从Sigslot开始讲解,但是我不打算现在对Sigslot进行展开,因为它还是很好理解的。不明白的朋友可以上网查询一下,或者姑且就把它当做函数回调(更精确地说它实现了C#的delegate)就可以了。在talk_base的多路信号分离器中只有少数几个地方使用了Sigslot,即使忽略它也不影响对多路信号分离器的理解。

 

1 event

 

event.h/event.cc文件中只有talk_base::Event类。

 

1.1 talk_base::Event

 

该类主要实现了跨平台的Win32 Event功能(正如前言中所说,本文假定读者已经很熟悉Win32平台的各种组件,如有不明白的地方可以参考MSDN)。talk_base::Event类的各个成员函数与Win32 Event所提供的API几乎一致,所以不再多做解释。

 

在Linux系统中,WebRTC使用了mutex和条件变量来实现Event的功能。首先,我将对Win 32 API和pthread API做一下类比:

 

CreateEvent

pthread_mutex_init、pthread_cond_init这两个函数用来创建pthread的mute和条件变量。

 

CloseHandle

pthread_mutex_destroy、pthread_cond_destroy这两个函数用来销毁pthread的mute和条件变量。

 

SetEvent

pthread_mutex_lock、pthread_mutex_unlock这两个函数加锁和解锁mutex,pthread_cond_broadcast函数用来解除所有等待在该条件变量上的线程的阻塞状态。

 

ResetEvent

pthrea_mutex_lock、pthread_mutex_unlock(已解释)

 

WaitForSingleObject

pthrea_mutex_lock、pthread_mutex_unlock(已解释)。pthrea_cond_wait函数用来使线程阻塞在条件变量上。

 

下面我将大致解释一下talk_base::Event类的实现原理:

 

talk_base::Event的主要功能由条件变量实现,mutex只是辅助条件变量起到锁的作用。条件变量的pthread_cond_wait和pthread_cond_broadcast函数与Win32 Event的WaitForSingleObject和SetEvent基本类似。talk_base::Event是否为signal状态由布尔类型的成员变量event_status_控制。是否为manual reset的Event由布尔类型的成员变量is_manual_reset_控制。与Win32 Event不同的状况主要体现在Event的manual reset控制上。

 

Linux系统下所有调用talk_base::Event::Wait函数的线程会阻塞在pthread_cond_wait函数上。当talk_base::Event::Set函数被调用时,pthread_cond_broadcast函数会解除所有等待在pthread_cond_wait函数上的线程的阻塞状态。这对于manual reset的Win32 Event来说没什么问题,问题出在auto reset的Win32 Event上。Auto reset的Win32 Event每次只能解除一条等待在Event上的线程的阻塞状态,其他线程依然为阻塞状态。这就需要mutex来配合实现了。

 

在这里要重点解释一下pthread_cond_wait函数的第二个参数pthread_mutex_t *mutex。当线程进入pthread_cond_wait函数时会解锁mutex,而在离开pthread_cond_wait时会重新加锁mutex。可以理解为:

 

[cpp] view plaincopy
  1. int pthread_cond_wait(pthread_cond_t *cond,pthread_mutex_t *mutex)  
  2. {  
  3.   pthread_mutex_unlock(mutex);  
  4.   …  
  5.   …  
  6.   …  
  7.   pthread_mutex_lock(mutex);  
  8.   return 0;  
  9. }  


这是Win32 没有的行为,需要特别注意。

 

有了以上的机制后,模拟auto rest的Win32 Event就没问题了。当第一条线程获得mutex锁并离开pthread_cond_wait函数时,其他线程会依然被阻塞在pthread_mutex_lock(mutex)函数上,无法离开pthread_cond_wait函数。那条成功离开线程会马上检测当前的talk_base::Event是否为manual reset的,如果不是就马上将event_status_成员变量设置为false,并解锁mutex。这时其他线程才能有机会离开pthread_cond_wait函数。不过当他们离开pthread_cond_wait后立即检测event_status_成员变量,如果为false就重新调用pthread_cond_wait函数。这就完美实现了Win32 Event的auto reset的语义。

 

条件变量和mutex的配合是talk_base::Event类的难点。如果读者还是不能完全理解,请仔细阅读以上3段的内容(也可以上网查找pthread_cond_wait函数),并结合event.cc的源代码反复揣摩,应该可以很快理解的(毕竟代码不多,而且也不是WebRTC中真正困难的部分),我就不再多做解释了(在后面的部分我会提供独立编译\trunk\talk\base\目录下的源代码的makefile脚本,读者可以编译后添加调试代码分析talk_base::Event的原理)。

 

在分析了talk_base::Event的源代码之后有个疑问,那就是为什么不用pthread_cond_signal函数实现Win32 Event的auto reset语义?由于时间的原因暂且不做深入地研究。



推荐阅读
  • 在多线程环境中,IpcChannel的性能表现并未如预期般优于Tcp和Http通道。实际测试结果显示,在IIS6中通过Remoting创建的Ipc通道,其速度比Tcp通道慢了约20倍。本文详细分析了这一现象的原因,并提出了针对性的优化建议,以提升IpcChannel在高并发场景下的性能表现。 ... [详细]
  • 技术分享:使用 Flask、AngularJS 和 Jinja2 构建高效前后端交互系统
    技术分享:使用 Flask、AngularJS 和 Jinja2 构建高效前后端交互系统 ... [详细]
  • 阿里巴巴终面技术挑战:如何利用 UDP 实现 TCP 功能?
    在阿里巴巴的技术面试中,技术总监曾提出一道关于如何利用 UDP 实现 TCP 功能的问题。当时回答得不够理想,因此事后进行了详细总结。通过与总监的进一步交流,了解到这是一道常见的阿里面试题。面试官的主要目的是考察应聘者对 UDP 和 TCP 在原理上的差异的理解,以及如何通过 UDP 实现类似 TCP 的可靠传输机制。 ... [详细]
  • Python多线程编程技巧与实战应用详解 ... [详细]
  • 在Cisco IOS XR系统中,存在提供服务的服务器和使用这些服务的客户端。本文深入探讨了进程与线程状态转换机制,分析了其在系统性能优化中的关键作用,并提出了改进措施,以提高系统的响应速度和资源利用率。通过详细研究状态转换的各个环节,本文为开发人员和系统管理员提供了实用的指导,旨在提升整体系统效率和稳定性。 ... [详细]
  • 优化后的标题:深入探讨网关安全:将微服务升级为OAuth2资源服务器的最佳实践
    本文深入探讨了如何将微服务升级为OAuth2资源服务器,以订单服务为例,详细介绍了在POM文件中添加 `spring-cloud-starter-oauth2` 依赖,并配置Spring Security以实现对微服务的保护。通过这一过程,不仅增强了系统的安全性,还提高了资源访问的可控性和灵活性。文章还讨论了最佳实践,包括如何配置OAuth2客户端和资源服务器,以及如何处理常见的安全问题和错误。 ... [详细]
  • Keepalived 提供了多种强大且灵活的后端健康检查机制,包括 HTTP_GET、SSL_GET、TCP_CHECK、SMTP_CHECK 和 MISC_CHECK 等多种检测方法。这些健康检查功能确保了高可用性环境中的服务稳定性和可靠性。通过合理配置这些检查方式,可以有效监测后端服务器的状态,及时发现并处理故障,从而提高系统的整体性能和可用性。 ... [详细]
  • C++ 异步编程中获取线程执行结果的方法与技巧及其在前端开发中的应用探讨
    本文探讨了C++异步编程中获取线程执行结果的方法与技巧,并深入分析了这些技术在前端开发中的应用。通过对比不同的异步编程模型,本文详细介绍了如何高效地处理多线程任务,确保程序的稳定性和性能。同时,文章还结合实际案例,展示了这些方法在前端异步编程中的具体实现和优化策略。 ... [详细]
  • 本文介绍了如何利用 Delphi 中的 IdTCPServer 和 IdTCPClient 控件实现高效的文件传输。这些控件在默认情况下采用阻塞模式,并且服务器端已经集成了多线程处理,能够支持任意大小的文件传输,无需担心数据包大小的限制。与传统的 ClientSocket 相比,Indy 控件提供了更为简洁和可靠的解决方案,特别适用于开发高性能的网络文件传输应用程序。 ... [详细]
  • Python全局解释器锁(GIL)机制详解
    在Python中,线程是操作系统级别的原生线程。为了确保多线程环境下的内存安全,Python虚拟机引入了全局解释器锁(Global Interpreter Lock,简称GIL)。GIL是一种互斥锁,用于保护对解释器状态的访问,防止多个线程同时执行字节码。尽管GIL有助于简化内存管理,但它也限制了多核处理器上多线程程序的并行性能。本文将深入探讨GIL的工作原理及其对Python多线程编程的影响。 ... [详细]
  • 如何利用Java 5 Executor框架高效构建和管理线程池
    Java 5 引入了 Executor 框架,为开发人员提供了一种高效管理和构建线程池的方法。该框架通过将任务提交与任务执行分离,简化了多线程编程的复杂性。利用 Executor 框架,开发人员可以更灵活地控制线程的创建、分配和管理,从而提高服务器端应用的性能和响应能力。此外,该框架还提供了多种线程池实现,如固定线程池、缓存线程池和单线程池,以适应不同的应用场景和需求。 ... [详细]
  • 本文深入解析了Java 8并发编程中的`AtomicInteger`类,详细探讨了其源码实现和应用场景。`AtomicInteger`通过硬件级别的原子操作,确保了整型变量在多线程环境下的安全性和高效性,避免了传统加锁方式带来的性能开销。文章不仅剖析了`AtomicInteger`的内部机制,还结合实际案例展示了其在并发编程中的优势和使用技巧。 ... [详细]
  • 并发编程入门:初探多任务处理技术
    并发编程入门:探索多任务处理技术并发编程是指在单个处理器上高效地管理多个任务的执行过程。其核心在于通过合理分配和协调任务,提高系统的整体性能。主要应用场景包括:1) 将复杂任务分解为多个子任务,并分配给不同的线程,实现并行处理;2) 通过同步机制确保线程间协调一致,避免资源竞争和数据不一致问题。此外,理解并发编程还涉及锁机制、线程池和异步编程等关键技术。 ... [详细]
  • 在Python多进程编程中,`multiprocessing`模块是不可或缺的工具。本文详细探讨了该模块在多进程管理中的核心原理,并通过实际代码示例进行了深入分析。文章不仅总结了常见的多进程编程技巧,还提供了解决常见问题的实用方法,帮助读者更好地理解和应用多进程编程技术。 ... [详细]
  • 在Python网络编程中,多线程技术的应用与优化是提升系统性能的关键。线程作为操作系统调度的基本单位,其主要功能是在进程内共享内存空间和资源,实现并行处理任务。当一个进程启动时,操作系统会为其分配内存空间,加载必要的资源和数据,并调度CPU进行执行。每个进程都拥有独立的地址空间,而线程则在此基础上进一步细化了任务的并行处理能力。通过合理设计和优化多线程程序,可以显著提高网络应用的响应速度和处理效率。 ... [详细]
author-avatar
手机用户2502885647_951
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有