我有一个类,我正在应用多线程。我想一次只允许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()
方法。它在另一个类中由类似的约定调用。 E.g。
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()
时,它一次只播放一个语音模式。
答案 0 :(得分: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
变量,这意味着没有语音提示会相互重叠,因为它们都必须等到在说话之前清除变量。我不能保证的是提示将被读取的顺序(即,控制消息处理队列),如果您在已经大声说出提示的情况下向队列提交多个提示。无论哪种方式,这都应该起作用。
答案 1 :(得分:1)
您的问题不明确,但您有一个静态的锁变量(_locker
) - 这意味着只有一个线程可以永远执行startSpeaking
at一时间目前尚不清楚你是否尝试让线程互相等待,或者你的问题是否因为不希望他们彼此等待。
无论哪种方式,像这样使用单个静态锁是明显可疑的,IMO。如果您真的只能有效地拥有此类的一个有用实例,请考虑将其设为单例。 (在设计方面通常不太好。)如果有多个独立实例可以,那么使独立,使_locker
变量成为实例变量。
(我也强烈建议您开始遵循.NET命名约定。)