Sondaż w odpowiedni sposób?

Jestem inżynierem oprogramowania / sprzętu z dużym doświadczeniem w technologiach C i embedded. Obecnie jestem zajęty pisaniem niektórych aplikacji w C# (. Net), które wykorzystują sprzęt do akwizycji danych. A teraz, dla mnie, pytanie:

Na przykład: mam maszynę, która ma wyłącznik końcowy do wykrywania ostatecznego położenia osi. Teraz używam modułu akwizycji danych USB do odczytu danych. Obecnie używam wątku do ciągłego czytania status portu.

Na tym urządzeniu nie ma funkcji przerwania.

Moje pytanie: czy to właściwa droga? Czy powinienem używać timerów, wątków lub zadań? Wiem, że sondaże to coś, czego większość z was "nienawidzi" , ale każda sugestia jest mile widziana!

Author: ChrFin, 2014-04-28

2 answers

IMO, zależy to w dużej mierze od Twojego środowiska, ale po pierwsze - w większości przypadków nie powinieneś już używać wątków. Tasks są wygodniejsze i bardziej wydajne rozwiązanie do tego.

  • Niska częstotliwość sondaży: Timer + sondaż w zdarzeniu Tick:
    Zegar jest łatwy w obsłudze i zatrzymaniu. Nie musisz się martwić o wątki / zadania działające w tle, ale obsługa odbywa się w głównym wątku

  • Średnia częstotliwość sondażu: Task + await Task.Delay(delay):
    await Task.Delay(delay) nie blokuje wątku puli wątków, ale ze względu na przełączanie kontekstu minimalne opóźnienie wynosi ~15ms

  • Wysoka częstotliwość sondaży: Task + Thread.Sleep(delay)
    można go używać z opóźnieniami 1ms-w rzeczywistości robimy to, aby przetestować nasze urządzenie pomiarowe USB

Można to zaimplementować w następujący sposób:

int delay = 1;
var cancellationTokenSource = new CancellationTokenSource();
var token = cancellationTokenSource.Token;
var listener = Task.Factory.StartNew(() =>
{
    while (true)
    {
        // poll hardware

        Thread.Sleep(delay);
        if (token.IsCancellationRequested)
            break;
    }

    // cleanup, e.g. close connection
}, token, TaskCreationOptions.LongRunning, TaskScheduler.Default);

W większości przypadków możesz po prostu użyć Task.Run(() => DoWork(), token), ale nie ma przeciążenia, aby dostarczyć opcję TaskCreationOptions.LongRunning, która mówi harmonogramowi zadań, aby nie używał normalnego nić-nić basenowa.
Ale jak widzisz {[2] } są łatwiejsze w obsłudze (i awaitstanie, ale nie ma zastosowania tutaj). Szczególnie "zatrzymanie" polega na wywołaniu cancellationTokenSource.Cancel() w tej implementacji z dowolnego miejsca w kodzie.

Możesz nawet udostępnić ten token w wielu akcjach i zatrzymać je jednocześnie. Również, jeszcze rozpoczęte zadania nie są uruchamiane, gdy token jest anulowany.

Możesz również dołączyć inną akcję do zadania, które ma zostać uruchomione po jednym zadaniu:

listener.ContinueWith(t => ShutDown(t));

To jest wykonywane po zakończeniu słuchacza i można zrobić cleanup (t.Exception zawiera wyjątek akcji zadania, jeśli nie powiodło się).

 36
Author: ChrFin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-16 18:03:14

IMO

Możesz stworzyć moduł z niezależnym wątkiem/zadaniem, które będzie regularnie sprawdzać port. W oparciu o zmianę danych, moduł ten wywoła zdarzenie, które będzie obsługiwane przez zużywające się aplikacje

 2
Author: Manish Dalal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-04-28 12:55:48