C# - Jak zaczekać z odpowiedzią?

0

Witam wszystkich.
Mam spory problem i nie wiem jak się do tego zabrać.
Napisałem pewny interfejs (biblioteka DLL) pomiędzy programem na PC a urządzeniem zewnętrznym na mikrokontrolerze.
Program uruchamia w mojej bibliotece metodę, która sprawdza stan urządzenia i oczekuje odpowiedzi true lub false.
Problem polega na tym, że czas w jakim otrzymuję odpowiedź z urządzenia to nawet 60 sekund a ja kompletnie nie wiem jak opóźnić zwrócenie odpowiedzi do programu do czasu otrzymania odpowiedzi z urządzenia.
Obecnie zrobiłem to prymitywnie w pętli:

public bool StatusPOS()
{
    for(int i=0; i<60000; i++)
    {
        Thread.Sleep(1);
        if(_status)
        {
            i = 60000;
        }
    }
    return _status;
}

Wszystko działa ok, ale może być sytuacja gdzie w tym czasie program próbuje wywołać inną metodę a powyższym kodem blokuję całą bibliotekę do czasu odpowiedzi z urządzenia.
Próbowałem Thread.Join(), ale to mi też blokuje.
Czy może ktoś mi podpowiedzieć jaką metodą powinienem to rozwiązać?

1

Jak nie chcesz blokować wątku to użyj Task.Delay()

1

najlepiej utworzyć wywołanie metody w oddzielnym wątku i zaczekać na odpowiedź np Task.Run() lub Thread

0

Mam wrażenie ,że tu potrzebny jest szerszy kontekst tego co chcesz zrobić. Wysyłasz zapytanie do jakiegoś serwera? Jeśli tak to powinieneś to zrobić asynchronicznie i poczekać na wykonanie się wątku poprzez Task.Wait albo przez await ale to zależy od tego co chcesz zrobić. Jak wygląda fragment kodu na który czekasz? Chociaż najprawdopodobniej operator await będzie najodpowiedniejszy.

0

Konkretnie to jest interface pomiędzy systemem kasowym a terminalem kart płatniczych.
Otrzymuję kwotę z systemu kasowego, wysyłam ją do terminala i tutaj muszę poczekać, ponieważ ktoś musi wyjąć kartę z portfela i ją przyłożyć.

2

Kurcze to dalej mało ,ale rozumiem czemu nie chcesz pokazać więcej. Ale potrzebna jest jedna informacja, to terminal wysyła informację gdy transakcja się dokonała? Ogólnie to kod na który czekasz umieść w metodzie zwracającej task i użyj operatora await.

Tutaj link jak to działa. Pierwsza odpowiedź zawiera całkiem prosty i dobry przykład.
https://stackoverflow.com/questions/14455293/how-and-when-to-use-async-and-await
Może to też się przydać:
https://stackoverflow.com/questions/4238345/asynchronously-wait-for-taskt-to-complete-with-timeout

0

Tak. To terminal wysyła informację o transakcji. W zasadzie teraz mam zrobione dwa "symulatory". Do systemu kasowego i do terminala. Muszę to połączyć i uporządkować bo teraz kod jest zagmatwany.
Bardzo dziękuję za pomoc.

2

@dix2402:

W jaki sposób odbierasz ten _status? jakiś event?

A nie dałoby się tu pobawić w jakieś kolejki czy coś w tym kierunku?

coś cyklicznie odpytuje kasę, a coś cyklicznie sprawdza czy jest jakaś zwrotka do przetworzenia?

chociaż nie wiem na ile jest to dobre rozwiązanie :P

i = 60000;

dziwnie to wygląda :P

0

@dix2402: Konkretnie to jest interface pomiędzy systemem kasowym a terminalem kart płatniczych.
Otrzymuję kwotę z systemu kasowego, wysyłam ją do terminala i tutaj muszę poczekać, ponieważ ktoś musi wyjąć kartę z portfela i ją przyłożyć.

Gdzieś masz ustawianie pola _status. Zatem zamiast czekać w pętli na tę zmianę możesz przerobić kod w taki sposób, aby zmiana _status jednocześnie rzucała eventem np. PaymentStatusChange + np. w konstruktorze klasy rzucającej tym eventem (albo w dziedziczącym z niej dekoratorze) dodajesz timer albo cokolwiek innego, co po upływie określonego czasu też rzuci eventemPaymentStatusChange.

_status o wartości true/false nic nie mówi o tym, co to pole zawiera, nie mówi tego ani nazwa pola, ani jego typ. Użyj enuma, np. PaymentStatus { Succeeded, Timeout }, dzięki temu jak wrócisz za pół roku do tego kodu, to nie będziesz musiał tracić czasu na zastanawianie się, co miałeś kiedyś na myśli.

Prefiksy _ przed polami są dyskusyjne, a na pewno są brzydkie.

Jeśli liczysz na to, że 60k * Delay(1) da Ci jedną minutę, to jesteś w dużym błędzie. Im krótszy czas czekania, tym rozbieżność jest większa, do tego sleep gwarantuje jedynie minimalny czas. Myślę, że reakcja na działanie użytkownika może spokojnie poczekać nawet i dwa rzędy wielkości dłużej (100ms). Jednak w modelu zdarzeniowym (moja pierwsza uwaga) nie będziesz miał w ogóle tego problemu, bo reakcja nastąpi praktycznie natychmiast, a jednocześnie nie będziesz obciążać CPU zbędną pętlą blokującą wątek, co z kolei oznacza, że w celu nieblokowania GUI aplikacji nie będziesz musiał tworzyć osobnego wątku na to czekanie.

1 użytkowników online, w tym zalogowanych: 0, gości: 1