我正在撰寫一個程式,它使用三個執行緒更新顯示,兩個執行緒都將影像寫入顯示表單,一個在需要時在兩者之間切換。我將在底部包含所有三個的代碼。我注意到,當沒有聲音提示中止talkingThread 和neutralThread 的創建和啟動時,談話影像會在那里停留幾秒鐘,持續時間各不相同。我懷疑這與執行緒末尾的 Sleep 呼叫有關,呼叫 Abort 實際上并沒有處理執行緒,直到睡眠被清除,但我不知道這是否會影響另一個執行緒的寫入能力顯示幕。有什么辦法可以確保執行緒更快地被處理掉?
中性回路 -
private void neutralLoop() //loop for switching to and maintaining the neutral images
{
while (true)
{
if (isBlinking) //if blinking is enabled, check whether or not to blink, and hold for 1 second if so
{
int blinkChance = rnd.Next(2);
if (blinkChance == 1)
{
myImage = this.neutralEyesClosedMap;
pictureBox1.Image = myImage;
Thread.Sleep(1000);
}
}
myImage = this.neutralEyesOpenMap; //replace neutral eyes open state, hold for 5 secs
pictureBox1.Image = myImage;
Thread.Sleep(5000);
}
}
談話回圈 -
private void talkingLoop() //loop for switching to and maintaining the talking images
{
while (true)
{
if (isBlinking) //if blinking is enabled, check whether or not to blink, and hold for 1 second if so
{
int blinkChance = rnd.Next(2);
if (blinkChance == 1)
{
myImage = this.talkingEyesClosedMap;
pictureBox1.Image = myImage;
Thread.Sleep(1000);
}
}
myImage = this.talkingEyesOpenMap; //replace neutral eyes open state, hold for 5 secs
pictureBox1.Image = myImage;
Thread.Sleep(5000);
}
}
開關回路
private void switchLoop()
{
neutralThread.Start();
while (true)
{
if (deviceMeter.MasterPeakValue > 0 && deviceMeter.MasterPeakValue < 1) //check for audio
{
if (talkingThread.ThreadState != ThreadState.Running && talkingThread.ThreadState != ThreadState.WaitSleepJoin) //if talkingThread isnt running (neutralThread is running), get rid of it and start talkingThread.
{
neutralThread.Abort();
talkingThread = new Thread(new ThreadStart(talkingLoop));
talkingThread.Start();
}
} else {
if (neutralThread.ThreadState != ThreadState.Running && neutralThread.ThreadState != ThreadState.WaitSleepJoin) //if neutralThread isnt running (talkingThread is running), get rid of it and start neutralThread.
{
talkingThread.Abort();
neutralThread = new Thread(new ThreadStart(neutralLoop));
neutralThread.Start();
}
}
}
}
uj5u.com熱心網友回復:
使用Thread.Abort()是一個可怕的想法,可能會導致各種問題。該示例看起來也是在后臺執行緒上修改 UI 元素,這也是不允許的,并且會導致各種問題。
取消某些正在運行的后臺任務的正確方法是合作進行。但是,看起來我們根本不需要使用任何后臺執行緒。我們需要的是一個狀態機和一個計時器。狀態機跟蹤我們處于什么狀態,使用什么影像,以及當我們在狀態之間切換時會發生什么。定時器用于在一段時間后觸發狀態更改。
可以為此使用 async/await,因為這將被編譯為狀態機。whileTask.Delay以可與 async/await 一起使用的方式包裝計時器。因此,據我所知,您可以像這樣重寫您的示例:
private async Task Loop()
{
while (true)
{
cts = new CancellationTokenSource(); // replace the cancellationToken source each iteration
try
{
if (isBlinking) {
int blinkChance = rnd.Next(2);
if (blinkChance == 1)
{
pictureBox1.Image = isneutral ? neutralEyesClosedMap : talkingEyesClosedMap;
await Task.Delay(1000, cts.Token);
}
}
pictureBox1.Image = isneutral ? neutralEyesOpenMap : talkingEyesOpenMap;
await Task.Delay(5000, cts.Token);
}
// Task.Delay may throw when isneutral changes state, this is expected, just continue
catch(OperationCanceledException){}
}
}
public async Task SetMasterPeakValue(double value)
{
var oldValue = isneutral;
isneutral = value > 0 && value < 1;
if (oldValue != isneutral)
{
cts.Cancel(); // cancel the current loop
}
}
據我所知,這應該保持相同的行為,同時在主執行緒上運行所有代碼,并避免執行緒的所有麻煩。請注意,這需要在談話/中立條件實際發生變化時通知班級,我的示例使用了一種方法,但它也可以是一個事件。您可能還需要某種方法來停止整個回圈,這可能是一個簡單的布林值或另一個取消令牌源。
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/347976.html
