Я тестирую класс, который оборачивает BackgroundWorker для выполнения операции вне потока пользовательского интерфейса в моем приложении.
Приведенный ниже тест не пройден, если превышен тайм-аут, и проходит, если progressEventCount достигает ожидаемого числа событий дозатем.
Мой вопрос касается синхронизации.asyncExecutor.Progressed запускается из потока пула потоков, который используется BackgroundWorker, и тестовый поток считывает его обратно в цикле while.
Правильно ли я использую блокировку?
[Test]
[Timeout(1250)]
public void Execute()
{
var locker = new object();
const int numberOfEvents = 10;
const int frequencyOfEvents = 100;
var start = DateTime.Now;
int progressEventCount = 0;
IGradualOperation tester = new TestGradualOperation(numberOfEvents, frequencyOfEvents);
var asyncExecutor = new AsynchronousOperationExecutor();
asyncExecutor.Progressed += (s, e) => { lock (locker) progressEventCount++; };
asyncExecutor.Execute(tester);
while (true)
{
int count;
lock (locker)
{
count = progressEventCount;
}
if (count < numberOfEvents) continue;
Assert.Pass("Succeeded after {0} milliseconds", (DateTime.Now - start).TotalMilliseconds);
}
}
// Implementation
public class AsynchronousOperationExecutor
{
public void Execute(IGradualOperation gradualOperation)
{
var backgroundWorker = new BackgroundWorker {WorkerReportsProgress = true};
backgroundWorker.DoWork += BackgroundWorkerDoWork;
backgroundWorker.ProgressChanged += BackgroundWorkerProgressChanged;
backgroundWorker.RunWorkerAsync(gradualOperation);
}
private void BackgroundWorkerProgressChanged(object sender, ProgressChangedEventArgs e)
{
var myArgs = e.UserState as ProgressEventArgs;
OnProgressed(myArgs);
}
static void BackgroundWorkerDoWork(object sender, DoWorkEventArgs e)
{
var workerThis = sender as BackgroundWorker;
var operation = e.Argument as IGradualOperation;
if (workerThis == null || operation == null) return;
operation.Progressed += (s, e1) => workerThis.ReportProgress((int)e1.Percentage, e1);
operation.Run();
}
private void OnProgressed(ProgressEventArgs e)
{
if (Progressed != null)
Progressed(this, e);
}
public event EventHandler<ProgressEventArgs> Progressed;
}
// Test Helper Class
public class TestGradualOperation : IGradualOperation
{
private readonly int _numberOfEvents;
private readonly int _frequencyMilliseconds;
public TestGradualOperation(int numberOfEvents, int frequencyMilliseconds)
{
_numberOfEvents = numberOfEvents;
_frequencyMilliseconds = frequencyMilliseconds;
}
public void Run()
{
for (int i = 0; i < _numberOfEvents; i++)
{
Thread.Sleep(_frequencyMilliseconds);
OnProgressed(new ProgressEventArgs(i, _numberOfEvents));
}
}
private void OnProgressed(ProgressEventArgs e)
{
if (Progressed != null)
Progressed(this, e);
}
public event EventHandler<ProgressEventArgs> Progressed;
}