Как реализовать состояние ожидания при использовании многопоточности в C # - PullRequest
0 голосов
/ 27 марта 2012

У меня есть класс, к которому я применяю многопоточность. Я хотел бы разрешить только 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() любым потоком она воспроизводила только один речевой паттерн за раз.

Ответы [ 2 ]

2 голосов
/ 17 июня 2013

Я знаю, что этот вопрос устарел, но если я правильно понимаю ваш вопрос (что вы хотите, чтобы все выступления были выполнены последовательно, как если бы это было сделано в одном потоке), вы можете сделать что-то вроде этого:

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, что будет означать, что никакие речевые запросы никогда не будут перекрывать друг друга, так как им всем придется ждать, покапеременная очищается, прежде чем говорить.То, что я не могу гарантировать, - это порядок чтения подсказок (т. Е. Контроль над очередью обработки сообщений), если вы отправляете в очередь несколько подсказок, когда подсказка уже произносится вслух.В любом случае, это должно сработать.

1 голос
/ 27 марта 2012

Ваш вопрос не ясен, но у вас есть единственная переменная блокировки (_locker), которая является статической - это означает, что только один поток может когда-либо выполнять startSpeaking одновременно.Не ясно, пытаетесь ли вы заставлять потоки ждать друг друга, или же ваш вопрос в том, что вы не хотите, чтобы они ждали друг друга.

В любом случае, использование такой статической блокировки, как это, явно сомнительно, ИМО.Если вы действительно можете иметь только один полезный экземпляр этого класса, подумайте о том, чтобы сделать его одиночным.(Обычно это нехорошо с точки зрения дизайна.) Если хорошо иметь несколько независимых экземпляров, то делает их независимыми, делая переменную _locker переменной экземпляра.

(я бытакже настоятельно советуем вам следовать следующим соглашениям об именах .NET.)

...