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()が任意のスレッドによって呼び出されたときに、一度に 1 つの音声パターンのみを再生するようにするにはどうすればよいかということです。

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。つまり、一度に実行できるスレッドは 1 つだけです。スレッドを相互に待機させようとしているのか、それとも相互に待機させたくないための質問なのかは明らかではありません。startSpeaking

いずれにせよ、このように単一の静的ロックを使用することは明らかに疑わしいです, IMO. このクラスの有用なインスタンスを実際に 1 つしか持てない場合は、それをシングルトンにすることを検討してください。(一般に、設計の観点からは好ましくありません。)複数の独立したインスタンスを使用しても問題ない場合は、変数をインスタンス変数にし、それらを独立させます。_locker

(また、.NET 命名規則に従うことを強くお勧めします。)

于 2012-03-27T07:21:00.897 に答える