You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在Xamarin中实现Azure TTS方法的互斥执行方案咨询

Xamarin中Azure TTS的互斥调用解决方案

问题背景

在Xamarin应用中集成Azure文本转语音(TTS)服务时,两个由定时器触发的方法(M1、M2)会调用TTS接口,需要确保同一时间只有一个TTS合成任务在执行,但使用Lock、Monitor、SemaphoreSlim等同步方式未解决并发问题。

问题根源

  1. TTS服务类的Speak方法使用async void,调用方无法等待其执行完成,导致同步机制无法生效。
  2. 定时器的Elapsed事件在独立线程触发,同步对象未在正确的异步上下文生效。

解决方案

1. 修改TTS服务类,引入异步安全的同步机制

在TextToSpeech类中使用SemaphoreSlim实现异步互斥,同时将Speak方法改为async Task以便调用方等待:

using Microsoft.CognitiveServices.Speech;

namespace PorjectB1.Model
{
    public class TextToSpeech
    {
        static private string speechKey { get; set; }
        static private string speechRegion { get; set; }
        // 初始化信号量,仅允许1个并发任务执行
        private readonly SemaphoreSlim _speechSemaphore = new SemaphoreSlim(1, 1);
        
        public TextToSpeech()
        {
            speechKey = "***";
            speechRegion = "***";
        }

        static void OutputSpeechSynthesisResult(SpeechSynthesisResult speechSynthesisResult, string text)
        {
            switch (speechSynthesisResult.Reason)
            {
                case ResultReason.SynthesizingAudioCompleted:
                    //Log Something
                    break;
                case ResultReason.Canceled:
                    //Log Something
                    break;
                default:
                    //Log Something
                    break;
            }
        }

        public async Task Speak(string text)
        {
            // 异步等待信号量,获取执行权限
            await _speechSemaphore.WaitAsync();
            try
            {
                var speechConfig = SpeechConfig.FromSubscription(speechKey, speechRegion);

                using (var speechSynthesizer = new SpeechSynthesizer(speechConfig))
                {
                    var speechSynthesisResult = await speechSynthesizer.SpeakTextAsync(text);
                    OutputSpeechSynthesisResult(speechSynthesisResult, text);
                }
            }
            finally
            {
                // 释放信号量,允许下一个任务执行
                _speechSemaphore.Release();
            }
        }
    }
}

2. 修改主页面代码,确保等待TTS任务完成

将主页面中的Speak方法改为异步方法,并在M1、M2中等待其执行完成,适配定时器线程的上下文:

namespace PorjectB1.Controller
{
    public partial class MainPage : ContentPage
    {
        private System.Timers.Timer m1Timer;
        private System.Timers.Timer m2Timer;
        static Model.TextToSpeech ttsService = new Model.TextToSpeech();

        public MainPage()
        {
            InitializeComponent();
            m1Timer= new System.Timers.Timer(15000);
            m1Timer.Elapsed += OnM1TimerElapsed;
            m1Timer.AutoReset = true;
            m1Timer.Enabled = true;
            m2Timer = new System.Timers.Timer(60000);
            m2Timer.Elapsed += OnM2Elapsed;
            m2Timer.AutoReset = true;
            m2Timer.Enabled = true;
        }

        private async void OnM1TimerElapsed(object sender, ElapsedEventArgs e)
        {
            await M1();
        }
        private async void OnM2Elapsed(object sender, ElapsedEventArgs e)
        {
            await M2();
        }

        private async Task M1()
        {
             string SpeechText=string.Empty;
             //Do Something...
             await Speak(SpeechText); 
        }

        private async Task M2()
        {
            string SpeechText=string.Empty;
             //Do Something...
             await Speak(SpeechText);  
        }

        private async Task Speak(string text)
        {
             await ttsService.Speak(text);
        }
    }
}

关键说明

  • SemaphoreSlim.WaitAsync():异步等待信号量,不会阻塞线程,完美适配异步场景下的并发控制。
  • 替换async void为async Task:让调用方能够等待TTS任务执行完成,确保同步机制真正生效。
  • finally块释放信号量:保证即使TTS任务抛出异常,信号量也能被正确释放,避免出现死锁情况。

内容的提问来源于stack exchange,提问作者Kadir Beskardes

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 12:59:00