news 2026/8/29 17:27:30

Linux PipeWire深度解析之pw_thread_loop_wait调用流程与实战(八十七)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Linux PipeWire深度解析之pw_thread_loop_wait调用流程与实战(八十七)

简介:CSDN博客专家、《Android系统多媒体进阶实战》作者

博主新书推荐:《Android系统多媒体进阶实战》🚀
Android Audio工程师专栏地址:Audio工程师进阶系列原创干货持续更新中……】🚀
Android多媒体专栏地址:多媒体系统工程师系列原创干货持续更新中……】🚀
专题一 二:AAOS车载系统+AOSP14系统攻城狮入门视频实战课🚀
专题三:Android14 Binder之HIDL与AIDL通信实战课🚀
专题四:Android15快速自定义与集成音效实战课🚀
专题五:Android15音频策略实战课🚀
专题六:Android15音频性能实战课(无声/杂音/断音/爆音实战案例)🚀

人生格言:人生从来没有捷径,只有行动才是治疗恐惧和懒惰的唯一良药.

更多原创,欢迎关注:Android系统攻城狮


🍉🍉🍉文章目录🍉🍉🍉

  • 🌻1.前言
      • 要点概括
  • 🌻2.应用场景与用法
    • 函数原型
    • 参数说明
    • 返回值
    • 应用场景
  • 🌻3.调用流程剖析
    • 🌻3.1核心步骤
    • 🌻3.2调用流程图
    • 🌻3.3生命周期图
  • 🌻4.实战应用案例
  • 🌻5.一句话总结

🌻1.前言

本篇目的:

Linux PipeWire深度解析之pw_thread_loop_wait调用流程与实战。

要点概括

  • 核心功能:让当前线程在PipeWireThread Loop锁保护下进入等待状态,直到其他线程调用pw_thread_loop_signal唤醒。

  • 工作机制:调用时要求已经持有loop锁,函数内部会释放锁并阻塞等待,收到signal后重新获得锁并返回。

  • 典型用途:等待PipeWire异步连接完成、等待Stream状态变化、等待对象创建完成、等待回调线程更新共享状态。

pw_thread_loop_wait的本质是线程同步接口,不是事件分发接口,也不是Graph处理接口。它不直接处理音频数据,不触发process回调,也不驱动PipeWire服务端工作。

它通常和pw_thread_loop_lock、pw_thread_loop_unlock、pw_thread_loop_signal配套使用。应用线程先加锁检查条件,如果条件未满足,就调用pw_thread_loop_wait等待;回调线程在状态变化后加锁更新条件,再调用pw_thread_loop_signal唤醒等待线程。

它和pw_thread_loop_timed_wait的区别是:pw_thread_loop_wait没有超时返回,只能等待signal唤醒;pw_thread_loop_timed_wait带超时时间,可以避免无限阻塞。它和pw_thread_loop_accept也不同,accept只用于配合signal的wait_for_accept握手机制,不是普通等待入口。

🌻2.应用场景与用法

pw_thread_loop_wait

是PipeWireThread Loop API中用于线程等待和条件同步的接口。

Thread Loop会把PipeWireLoop运行在独立线程中,应用线程可以通过Thread Loop锁保护共享状态。由于PipeWire连接、注册表事件、Stream状态变化等操作都可能通过异步回调完成,所以应用经常需要等待某个状态从“未完成”变成“已完成”。

pw_thread_loop_wait用于在持有Thread Loop锁时释放锁并等待其他线程调用pw_thread_loop_signal唤醒。

函数原型

voidpw_thread_loop_wait(structpw_thread_loop*loop);

参数说明

structpw_thread_loop*loop;

loop表示已经创建的PipeWireThread Loop对象。

调用该函数前,当前线程必须已经调用pw_thread_loop_lock持有该loop的锁。该函数内部会临时释放锁,使其他线程或回调可以进入临界区更新状态。被pw_thread_loop_signal唤醒后,它会重新获得锁,然后返回到调用点。

返回值

该函数没有返回值。

void

由于没有返回值,调用者不能通过返回码判断等待原因。工程上通常使用“条件变量模式”处理:wait返回后再次检查业务条件,而不是假设signal一定表示目标状态已经满足。

典型写法如下:

pw_thread_loop_lock(loop);while(!done)pw_thread_loop_wait(loop);pw_thread_loop_unlock(loop);

这里必须使用while检查条件,而不是只用if。因为线程可能被唤醒后发现条件仍未满足,也可能存在多个等待线程共享同一个signal。

应用场景

第一类场景是等待PipeWire连接完成。

应用创建pw_context、pw_core或pw_stream后,连接过程通常伴随异步事件。主线程可以等待回调线程更新connected状态,避免在对象未准备完成时继续访问后续资源。

第二类场景是等待Stream进入目标状态。

播放或录音应用调用pw_stream_connect后,Stream状态会通过state_changed回调上报。应用线程可以通过pw_thread_loop_wait等待Stream进入PAUSED、STREAMING或ERROR状态。

第三类场景是等待全局对象发现完成。

客户端连接PipeWireCore后,Registry会异步上报Node、Device、Factory、Metadata等全局对象。应用如果需要等待目标对象出现,可以在registry回调中更新状态并signal。

第四类场景是同步业务线程和PipeWire事件线程。

应用线程负责创建对象和发起请求,Thread Loop线程负责事件处理和回调执行。pw_thread_loop_wait把这两类线程用同一把锁和signal机制串起来,避免忙等和竞态。

🌻3.调用流程剖析

🌻3.1核心步骤

1.应用调用pw_thread_loop_new创建Thread Loop对象。

2.应用调用pw_thread_loop_start启动独立Loop线程。

3.应用线程调用pw_thread_loop_lock进入受保护临界区。

4.应用线程检查业务条件,例如connected、ready、done、error等状态。

5.如果条件已经满足,应用线程直接继续执行。

6.如果条件未满足,应用线程调用pw_thread_loop_wait进入等待。

7.pw_thread_loop_wait内部释放Thread Loop锁,使回调线程可以更新共享状态。

8.回调线程在状态变化时持有同一把锁,更新业务条件。

9.回调线程调用pw_thread_loop_signal唤醒等待线程。

10.pw_thread_loop_wait被唤醒后重新获得Thread Loop锁,并返回调用点。

11.应用线程再次检查条件,条件满足后调用pw_thread_loop_unlock退出临界区。

12.如果条件仍未满足,应用线程继续调用pw_thread_loop_wait等待下一次signal。

🌻3.2调用流程图

🌻3.3生命周期图

🌻4.实战应用案例

下面以“等待Stream状态变化”为例,说明pw_thread_loop_wait在真实开发中的用法。

应用调用pw_stream_connect后,Stream状态不会立即变成目标状态。状态变化会通过pw_stream_events.state_changed回调异步通知。主线程如果需要等待Stream进入PAUSED或STREAMING状态,就可以使用pw_thread_loop_wait。

structapp_data{structpw_thread_loop*loop;structpw_stream*stream;bool stream_ready;bool stream_error;};staticvoidon_stream_state_changed(void*userdata,enumpw_stream_stateold,enumpw_stream_statestate,constchar*error){structapp_data*app=userdata;pw_thread_loop_lock(app->loop);switch(state){casePW_STREAM_STATE_PAUSED:casePW_STREAM_STATE_STREAMING:app->stream_ready=true;break;casePW_STREAM_STATE_ERROR:casePW_STREAM_STATE_UNCONNECTED:app->stream_error=true;break;default:break;}pw_thread_loop_signal(app->loop,false);pw_thread_loop_unlock(app->loop);}

state_changed回调中只做三件事:加锁、更新状态、发送signal。这样可以保证应用线程看到的stream_ready和stream_error状态是受锁保护的,不会出现读写竞态。

主线程等待状态变化时,使用while循环检查条件。

staticintwait_stream_ready(structapp_data*app){intret=0;pw_thread_loop_lock(app->loop);while(!app->stream_ready&&!app->stream_error)pw_thread_loop_wait(app->loop);if(app->stream_error)ret=-1;pw_thread_loop_unlock(app->loop);returnret;}

这段代码的关键点不是“等待一次signal”,而是“等待条件成立”。signal只是唤醒手段,真正决定是否继续执行的是stream_ready和stream_error。

完整使用链路通常如下:

staticconststructpw_stream_eventsstream_events={PW_VERSION_STREAM_EVENTS,.state_changed=on_stream_state_changed,};staticintsetup_stream(structapp_data*app){intret;app->stream_ready=false;app->stream_error=false;app->loop=pw_thread_loop_new("stream-loop",NULL);if(app->loop==NULL)return-1;ret=pw_thread_loop_start(app->loop);if(ret<0)returnret;pw_thread_loop_lock(app->loop);app->stream=pw_stream_new_simple(pw_thread_loop_get_loop(app->loop),"playback-stream",NULL,&stream_events,app);if(app->stream==NULL){pw_thread_loop_unlock(app->loop);return-1;}/* * 这里通常继续调用pw_stream_connect。 * connect后状态通过state_changed异步返回。 */pw_thread_loop_unlock(app->loop);ret=wait_stream_ready(app);if(ret<0)returnret;return0;}

这个案例中,pw_thread_loop_wait负责解决“同步线程等待异步回调结果”的问题。应用线程不需要轮询状态,也不需要sleep等待。回调线程只要在状态变化后调用pw_thread_loop_signal,等待线程就可以被及时唤醒。

工程上要特别注意三点。

第一,调用pw_thread_loop_wait前必须先调用pw_thread_loop_lock。否则等待和状态更新不在同一个同步模型中,容易产生竞态。

第二,wait返回后必须重新检查条件。不要把signal理解成“目标状态一定完成”,signal只表示“有线程通知你重新检查状态”。

第三,不要在持锁状态下执行耗时操作。Thread Loop回调也会在锁保护下执行,长时间占用锁会阻塞PipeWire事件处理,导致状态通知、对象创建或Stream处理延迟。

pw_thread_loop_wait常见错误写法如下:

pw_thread_loop_lock(loop);if(!ready)pw_thread_loop_wait(loop);pw_thread_loop_unlock(loop);

这段代码只检查一次ready。如果线程被唤醒后ready仍然为false,后续逻辑仍会继续执行,容易访问未初始化对象。

更安全的写法是:

pw_thread_loop_lock(loop);while(!ready&&!error)pw_thread_loop_wait(loop);pw_thread_loop_unlock(loop);

这样可以同时处理正常完成、错误退出和重复唤醒问题。

🌻5.一句话总结

pw_thread_loop_wait是PipeWireThread Loop中的等待同步接口:调用线程必须先持有loop锁,wait内部释放锁并等待pw_thread_loop_signal唤醒,返回后重新持锁,适合等待连接、状态变化和异步回调结果。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/29 17:24:52

【关注可白嫖源码】--课程设计--毕业设计--基于Spring Boot+ECharts的NBA数据智慧分析平台[编号:project31971](案件分析)

本文仅展示核心实现逻辑与部分代码片段&#xff0c;完整项目源码、配套文档、数据库脚本内容较多&#xff0c;篇幅有限无法全部放出。有需要完整资源的同学&#xff0c;可以在评论区留言【资料或领源码】&#xff0c;我会一一回复站内私信&#xff0c;发送完整文件摘 要传统的…

作者头像 李华
网站建设 2026/8/29 17:16:58

Socat 命令总结

事以密成&#xff0c;语以泄败。 导航 介绍 基本语法 用法示例 1. 回显输入2. 回显输入 over TCP/UDP3. 正向连接 shell4. 反向连接 shell5. 端口转发6. 网络服务7. 文件传输8. 管道传输9. 加密传输10. TUN 网络 杂项 介绍Socat 是一个功能强大的网络工具&#xff08;相当于…

作者头像 李华
网站建设 2026/8/29 17:14:50

网易NLP算法工程师校招笔试全解析:考点、套路与避坑指南

每年这个时候&#xff0c;都有不少同学来问我同一件事&#xff1a;网易的NLP算法工程师校招笔试题到底难不难、考什么、怎么准备。我自己经历过2018年那场笔试&#xff0c;后来也帮部门出过类似年份的校招笔试题&#xff0c;所以对这个“网易2018校招NLP算法工程师笔试卷”背后…

作者头像 李华
网站建设 2026/8/29 17:14:41

Python控制流深度解析:条件判断、循环与流程控制实战指南

1. 项目概述&#xff1a;为什么控制流是编程的“方向盘”&#xff1f;刚接触Python那会儿&#xff0c;我总觉得变量、数据类型这些是“硬骨头”&#xff0c;啃下来就能写程序了。直到我尝试写一个最简单的猜数字游戏&#xff0c;才发现事情没那么简单。程序怎么知道用户猜的数字…

作者头像 李华
网站建设 2026/8/29 17:14:17

仿微信H5聊天室源码解析:多人群聊IM系统搭建与部署

简介&#xff1a;即时通讯&#xff08;IM&#xff09;已渗透到社交、客服、社群运营等众多业务场景。实现一个可落地的聊天系统&#xff0c;关键在于消息的实时推送与可靠存储。WebSocket作为全双工通信协议&#xff0c;是构建多人群聊、消息广播的核心技术底座。从账号体系到消…

作者头像 李华
网站建设 2026/8/29 17:12:49

STM32H5 DA调试认证证书链命令行批量生成与产线自动化实践

最近在搞STM32H5的安全产线方案&#xff0c;调试口保护这块绕不开DA证书链。最开始我图省事&#xff0c;直接在STM32TrustedPackageCreator里点鼠标&#xff0c;点完发现一个严重问题&#xff1a;产线几十块板子&#xff0c;每块板子的证书都不一样&#xff0c;GUI点一次可以&a…

作者头像 李华