c # — Странное поведение в последовательности выполнения. Темы, асинхронность и ожидание включены

Этот код в основном предназначен для обработки изображений, но я испытываю не синтаксическую ошибку «Мы думаем, что это многопоточность». Я работаю над приложением, которое я не написал. Эти коды представляют собой несколько файлов .cpp / c #. Он работал нормально, но внезапно начал вести себя странно.

Обычно пользователь делает снимок и на line 85, перед switch(), шаг управления в несколько функций, чтобы в конечном итоге в последнем файле (1-> 6). Когда этот последний файл (6) завершает выполнение, управление возвращается обратно (6-> 1), и мы получаем «case«к первому файлу, чтобы затем ввести switch(), выполнить и продолжить.

1:

     private async void measureButton_Click(object sender, RoutedEventArgs e)
{
// ..
// some code above
var result = await ((CaptureViewModel)DataContext).ProcessMeasurement(); // line 85

switch (result) // line 87 <<< Here the switch executes before line 85 finishes executing
{
// some  code and cases below
// ....

2:

public async Task<AnalyzeCode> ProcessMeasurement()
{
if (currentSession.Type == SessionType.Calibration)
return await TakeCalibrationImage();

return AnalyzeCode.NoSessionSelected;
}

3:

public async Task<AnalyzeCode> TakeCalibrationImage()
{
if (calibrationData.Count < maxCalibrationImages)
{
try
{
var data = await cameraController.TakeMeasurement(currentSession.Calibration, SessionType.Calibration);
// some code below
// ..

4:

public async Task<Measurement> TakeMeasurement(Calibration calibration, SessionType type)
{
try
{
switch (type)
{
case SessionType.Calibration:
// some code above
// ..
return await cameraClient.AnalyzeNextCalibrationAsync(); // line 518 Here it throws an exception error
// some code below
//..

5:

IObservable<Measurement>^ Client::AnalyzeNextCalibrationAsync()
{
return Observable::ObserveOn(
Observable::SubscribeOn(
Observable::Create<Measurement>(
gcnew Func<IObserver<Measurement>^, Action^>(
gcnew AnalyzeNextCalibrationSubscribeFactory(this),
&AnalyzeNextCalibrationSubscribeFactory::AnalyzeNext)),
Scheduler::TaskPool),
Scheduler::TaskPool);
}
class on_next_functor_3
{
public:
void operator ()(const tuple<frame, frame>& pair) const
{
Action<Measurement>^ on_next_delegate = this->on_next_delegate;
on_next_delegate(ConvertToCalibrationMeasurement(pair));
}
};

6:

Measurement ConvertToCalibrationMeasurement(const tuple<frame, frame>& pair)
{
// ...
// more code above
auto result1 = find_calibration_pattern(master_image); // line 386
auto result2 = find_calibration_pattern(slave_image); // line 387
// ..
// some code
// ..
return Measurement( // line 401
masterImage,
slaveImage,
ConvertToDateTime(master.time),
ConvertToTargets(result));
} // end of the function

Теперь вот недавнее странное поведение. Элемент управления вводит 6 и начинает выполнять оператор за оператором, затем внезапно элемент управления возвращается к 4, выдает ошибку и полностью возвращается к началу и выполняет switch() который выскакивает ошибку на экране. Затем управление возвращается к line 387 в самом конце и продолжает выполнение этой функции. Так что технически он выполняет switch() в 1, прежде чем предыдущий оператор завершает выполнение. Тогда каким бы ни был результат в самом конце, он не будет полезен, так как наш случай «сбой» уже выполнен.

Кто-нибудь на земле знает, почему это произошло? где бы возникла эта проблема? и как это исправить? Спасибо

Редактировать:

Окно «Вывод» показывает это, как только появляется сообщение об ошибке switch()) pops:

Exception thrown: 'System.InvalidOperationException' in System.Reactive.Linq.dll
The thread 0x1574 has exited with code 0 (0x0).
Exception thrown: 'System.NullReferenceException' in App.exe

И это происходит в catch() файла 4 строки 518

Окно потока показывает, что Main Thread имеет элемент управления (желтая стрелка) полностью из файла 1-> 4. Однако, как только файл 4 вызывает 5-> 6, Main Thread теряет контроль, и «желтая стрелка» переходит к Worker Thread выполнение 6. Теперь, выполняя 6, Main Thread возвращает управление в 4, генерирует исключение и выполняет catch() но затем теряет контроль, чтобы вернуться к этому Worker Thread и продолжить выполнение 6 .. Это нормально? Я никогда не работал с потоками, но это не логично, и я никогда не видел «обрыва потока» при выполнении функции возврата, а затем перемотки вперед и продолжения. Мне нравится учебная часть, но это смущает новичка ..

2

Решение

Две возможные причины.

  1. Возможно, вы выполняете свой код два раза одновременно. Возможно, в разных потоках одновременно (если да, это должно быть легко увидеть в отладчике, откройте представление «Потоки»). Возможно, в том же потоке (возможно, если поток вызвал await, реализация запустила некоторую асинхронную операцию, поток освободился и снова вызвал await).

  2. Отладчик VS не всегда надежен. При отладке многопоточного кода иногда я вижу странные адреса, но это просто неправда. Для проверки добавьте запись о регистрации в строку 87, например, Debug.WriteLine, если это C #.

0

Другие решения

Других решений пока нет …