我遇到了后台工作者的问题。 我不知道如何描述它。 实际上它是一个游戏和背景工作者x x milisecs我更新进度条,检查是否有人丢失/赢了或时间到了。 如果有人赢了比赛就结束了。 如果两名球员都输了/时间到了,那么比赛将进入下一轮。 当两名球员输球时都会出现问题。 SetTime方法中的方法NextRound, 跑了两次。 这是代码:
void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
this.SetTime(e.ProgressPercentage);
}
void bw_DoWork(object sender, DoWorkEventArgs e)
{
Thread.Sleep(3000);
BackgroundWorker worker = sender as BackgroundWorker;
int tick = ProgLib.maxTime * 10;
for (int i = 1; i <= 100; i++)
{
if ((worker.CancellationPending == true))
{
e.Cancel = true;
break;
}
else
{
// Perform a time consuming operation and report progress.
Thread.Sleep(tick);
worker.ReportProgress(i);
}
}
}
private void SetTime(double k)
{
this.time.Bar1.Value = k;
this.time.Bar2.Value = k;
if (k >= 100 || (Gallery1.hasLost() && Gallery2.hasLost()) || ((Gallery1.isWinner() || Gallery2.isWinner())))
{
if (bw == null)
return;
bw.CancelAsync();
bw.Dispose();
bw = null;
saveData();
ProgLib.isAnyoneWinner(Gallery1.isWinner(), Gallery2.isWinner());
if (ProgLib.gameHasended())
{
gameHasEnded();
}
else
{
next_round();
}
}
}
private void next_round()
{
Thread nextRoundThread = new Thread((Object Send) =>
{
MainThread.Send((Object send) =>
{
Gallery1.hidePanel.Visibility = Visibility.Visible;
Gallery2.hidePanel.Visibility = Visibility.Visible;
ProgLib.nextLetter();//goes to next letter
LetterToPlay1.setLetter(ProgLib.getArrabicLetter(ProgLib.getCurentLetter()));//sets the next letter
LetterToPlay2.setLetter(ProgLib.getArrabicLetter(ProgLib.getCurentLetter()));
}, null);
Thread SoundThread = new Thread((Object send) =>
{
//Here Must Delay enought so the animation stops the hear the bell and the the letter, and then the game starts
Thread.Sleep(1800);
ProgLib.playOtherSound(ProgLib.Sounds.Chimes);//Bell Sound
Thread.Sleep(100);
//ProgLib.PlayLetterSound(ProgLib.getCurentLetter());//Letter Sound
ProgLib.playOtherSound(ProgLib.Sounds.Cat_Yawn);//TestOnly
});
SoundThread.IsBackground = true;
SoundThread.Start();
Thread.Sleep(3000);
MainThread.Send((Object send) =>
{
Gallery1.refresh();//galleries refresh so that the magician hides.
Gallery2.refresh();//
Gallery1.hidePanel.Visibility = Visibility.Hidden;//hide the Big Magician of mistakes
Gallery2.hidePanel.Visibility = Visibility.Hidden;
}, null);
});
nextRoundThread.IsBackground = true;
nextRoundThread.Start();
bw = new BackgroundWorker();
bw.WorkerSupportsCancellation = true;
bw.WorkerReportsProgress = true;
bw.DoWork += new DoWorkEventHandler(bw_DoWork);
bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);
bw.RunWorkerAsync();
}
答案 0 :(得分:3)
您的代码中存在线程竞争。您的工作人员将调用ReportProgress()并立即迭代循环。通过CancellationPending属性检查并再次入睡。
您的SetTime()方法稍后运行 。并调用CancelAsync(),但由于工作人员正在休眠,因此完全没有任何影响。直到它再次唤醒,再次调用ReportProgress(),迭代循环并然后将CancellationPending设置为true。
即使您已经结束游戏,也会再次调用您的SetTime()方法。
线程充斥着这样的问题。创可贴是在Sleep()调用后检查CancellationPending。其中99.999%的工作时间。达到100%需要使用适当的锁定进行非常激烈的重写。