0

我有一个要应用多线程的类。我想一次只允许 1 个线程“startSpeaking()”。这是我的尝试:

class VoiceEffect
{
    SpeechSynthesizer reader = new SpeechSynthesizer();

    static readonly object _locker = new object();

    public void createVoiceThread(string str)
    {
        Thread voicethread = new Thread(() => startSpeaking(str)); // Lambda Process
        voicethread.IsBackground = true;
        voicethread.Start();
    }
    public void startSpeaking(string str)
    {
        lock (_locker)
        {
            reader.Rate = -2; // Voice  effects.
            reader.Volume = 100;
            reader.Speak(str);
        }
    }
}

我也在createVoiceThread()从另一个类调用方法。它由另一个类中的类似约定调用。例如

class Program
{
    static void Main(string[] args)
    {
        VoiceEffect ve = new VoiceEffect();
        string text = "Hello world, how are you today? I am super-duper!!";

       for( int i=0 ; i < 10 ; i++ )
       {
          ve.createVoiceThread(text);
          ve.startSpeaking(text);

          Thread.Sleep(1000);
       }
    }
}

我的问题是如何修改这个程序,以便在startSpeaking()被任何线程调用时,它一次只播放一个语音模式。

4

2 回答 2

2

我知道这个问题已经过时了,但是如果我正确理解了您的问题(您希望所有演讲都按顺序完成,就好像它是在一个线程上完成的一样),您可以执行以下操作:

static class VoiceEffect
{
    SpeechSynthesizer reader = new SpeechSynthesizer();
    private volatile bool _isCurrentlySpeaking = false;

    /// <summary>Event handler. Fired when the SpeechSynthesizer object starts speaking asynchronously.</summary>
    private void StartedSpeaking(object sender, SpeakStartedEventArgs e)
    { _isCurrentlySpeaking = true; }
    /// <summary>Event handler. Fired when the SpeechSynthesizer object finishes speaking asynchronously.</summary>
    private void FinishedSpeaking(object sender, SpeakCompletedEventArgs e)
    { _isCurrentlySpeaking = false; }

    private VoiceEffect _instance;
    /// <summary>Gets the singleton instance of the VoiceEffect class.</summary>
    /// <returns>A unique shared instance of the VoiceEffect class.</returns>
    public VoiceEffect GetInstance()
    {
        if(_instance == null)
        { _instance = new VoiceEffect(); }
        return _instance;
    }

    /// <summary>
    /// Constructor. Initializes the class assigning event handlers for the
    /// SpeechSynthesizer object.
    /// </summary>
    private VoiceEffect()
    {
        reader.SpeakStarted += new EventHandler<SpeakStartedEventArgs>(StartedSpeaking);
        reader.SpeakCompleted += new EventHandler<SpeakCompletedEventArgs>(FinishedSpeaking);
    }

    /// <summary>Speaks stuff.</summary>
    /// <param name="str">The stuff to speak.</param>
    public void startSpeaking(string str)
    {
        reader.Rate = -2; // Voice  effects.
        reader.Volume = 100;

        // if the reader's currently speaking anything,
        // don't let any incoming prompts overlap
        while(_isCurrentlySpeaking)
        { continue; }

        reader.SpeakAsync(str);
    }

    /// <summary>Creates a new thread to speak stuff into.</summary>
    /// <param name="str">The stuff to read.</param>
    public void createVoiceThread(string str)
    {
        Thread voicethread = new Thread(() => startSpeaking(str)); // Lambda Process
        voicethread.IsBackground = true;
        voicethread.Start();
    }        
}

这为您提供了一个将管理所有线程的单例类,并且所有线程将共享该_isCurrentlySpeaking变量,这意味着任何语音提示都不会相互重叠,因为它们都必须等到变量被清除后才能说话。我不能保证读取提示的顺序(即,控制消息处理队列),如果您在已经大声说出提示的情况下向队列提交多个提示。无论哪种方式,这应该很有效。

于 2013-06-17T17:53:33.897 回答
1

您的问题不清楚,但是您有一个_locker静态的锁变量 ( ) - 这意味着一次只能执行一个线程startSpeaking。目前尚不清楚您是否试图让线程相互等待,或者您的问题是否是因为您希望它们相互等待。

无论哪种方式,像这样使用单个静态锁显然是可疑的,IMO。如果您真的只能有效地拥有此类的一个有用实例,请考虑将其设为单例。(通常在设计方面不好。)如果有多个独立实例很好,那么通过使变量成为实例变量来使它们独立。_locker

(我还强烈建议您开始遵循 .NET 命名约定。)

于 2012-03-27T07:21:00.897 回答