Hello! There is a program that works with an external oscilloscope. The oscilloscope starts when the OnDataReadyEventHandler event OnDataReadyEventHandler . It is necessary to suspend the main thread and wait for the end of the event.

 _OscDevice.OnDataReady += OnDataReadyEventHandler; // Регистрируем обработчик события о готовности данных измерений 

The event occurs when the Begin () function is called;

 private void button2_Click_3(object sender, EventArgs e) { Load_Data(); Thread.Sleep(250); Begin();//получение данных с осциллографа //Здесь нужно сделать ожидание обработки события OnDataReadyEventHandler,чтобы при следующем вызове функции Begin() не было конфликта из-за обращения к используемому объекту при следующем вызове Begin() ........ Begin(); } 

Handler itself:

 private void OnDataReadyEventHandler(uint nChannelsMask) { // !!! Не отображайте результаты на форме в данной функции - это будет приводить к ошибкам. // !!! Отображайте результаты в ф-ции ProcessData(). SafeProcessData(nChannelsMask); } private void SafeProcessData(uint nChannelsMask) { if (InvokeRequired) Invoke(new InvokeDelegateForProcessData(ProcessData), new Object[] { nChannelsMask }); else ProcessData(nChannelsMask); } 
  • Something you are doing wrong. The main thread cannot be stopped. Tell us better what you really want to achieve. - VladD
  • You understand, if you stop the main thread and wait until the OnDataReady event occurs, the window will noticeably freeze? Maybe you should change the logic of the program? - cybrex
  • task: to conduct a series of measurements using an oscilloscope. teams are exchanged via com-port. the protocol is as follows: a command to start the change of 0xFF is sent to the meter, after some time a signal of fitness or rejection, 'g' or 'b', comes to the computer. And with repeated measurement of for (...) {Begin ()}, the meter will send several 0xFF in a row without waiting for the measurement result - Shach
  • Therefore, I have a suspicion that the com-port does not wait for the result of the oscilloscope, and the result of the oscilloscope is formed in the event - Shach
  • one
    Work with devices in general must be removed from the main thread. - VladD

2 answers 2

It is impossible to stop the main thread. But, as I understand it, you don’t need it - you just have to wait until the end of the asynchronous operation before continuing?

For such cases asynchronous programming is invented. Let the Begin function return a task that will go to the completed state after receiving the event.

Then your handler will look like this:

 private async void button2_Click_3(object sender, EventArgs e) { Load_Data(); await Task.Delay(250); await Begin();//получение данных с осциллографа ........ await Begin(); } 

Now there are two things left. The first is to return the task from the Begin function. This is done something like this:

 private TaskCompletionSource<object> tcs; private Task Begin() { if (tcs != null) throw new InvalidOperationException("Операция уже выполняется"); var tcs_local = tcs = new TaskCompletionSource<object>(); // Тут остается старый код этой функции return tcs_local.Task; // Важно использовать именно локальную переменную - потому что к этому моменту tcs может оказаться уже снова null. } private void OnDataReadyEventHandler(uint nChannelsMask) { SafeProcessData(nChannelsMask); if (tcs != null) { var tcs_local = tcs; tcs = null; tcs_local.SetResult(null); // Главный поток сразу после этой строчки может начать новую операцию - поэтому важно установить tcs в null заранее } } 

At the same time, we received a completely free check of the execution time for the simultaneous execution of operations.

The second thing is that it is necessary to somehow block the button being pressed during the operation - since we did everything so well that the user can now press the button again during the process of pressing the button.

Well, the third point. In the code above, I assumed that the OnDataReadyEventHandler event can occur only when we are waiting for it. If the oscilloscope can throw it out at any time - then you should attend to atomic access to the variable tcs . Fortunately, all that is needed here is the Interlocked.CompareExchange operation in the Begin - and Interlocked.Exchange method in the event handler.

  • Oh, wrong. There is a double Begin , not a Begin / End . - VladD
  • @VlaD Thank you, I would have been able to end a long time without you. True, between actions I had to put await Task.Delay (). As for re-clicking: button1. Enabled = false; ... button1. Enabled = true; does not roll: (On the third note: the OnDataReadyEventHandler event occurs only when we are waiting for this. In the Begin () method, the Osc function is called. Run = 1, which starts the oscilloscope and triggers the event. - Shach
  • @Shach: your comment is most likely addressed to the author of the answer - VladD
  • @PavelMayorov: the comment seems to be for you. - VladD
  • @Shach, for me there is no reason that an ellipsis is worth it - which is necessary according to the logic of working with the device, this should be set. About the "non-rolling" button1. Enabled = false button1. Enabled = false - is there anything that the handler is called button2_Click_3 ? :) - Pavel Mayorov

In general, you need synchronization objects, you can do so.

 // создаём объект синхронизации не взведённым AutoResetEvent sync = new AutoResetEvent(false); private void button2_Click_3(object sender, EventArgs e) { Load_Data(); Thread.Sleep(250); Begin();//получение данных с осциллографа // ждём когда его установят в true sync.WaitOne(); ........ Begin(); } private void OnDataReadyEventHandler(uint nChannelsMask) { SafeProcessData(nChannelsMask); // устанавливаем sync.Set(); } 
  • when adding sync.WaitOne (), the debugger does not reach sync.Set () in the event. When commenting, sync.WaitOne () comes up. - Shach