Domanda

VB.NET 2010, .NET 4

Ciao a tutti,

Ho un oggetto System.Timers.Timer che fa un certo lavoro sul suo evento trascorso:

Private Sub MasterTimer_Elapsed(ByVal sender As Object, ByVal e As System.Timers.ElapsedEventArgs) Handles MasterTimer.Elapsed
    MasterTimer.Enabled = False
    '...work...
    MasterTimer.Enabled = True
End Sub

Il mio problema è che il lavoro che si sta facendo a volte si blocca. Parte del lavoro è la comunicazione seriale in modo che potrebbe essere sempre in attesa bloccato per una risposta da qualcosa. Ho già modificato il mio codice di comunicazione di serie un po 'per risolvere il problema si spera. Tuttavia, questo timer è fondamentalmente il battito cardiaco di un'applicazione di controllo di produzione ed è molto male se dovesse fermarsi per qualsiasi motivo. Stavo pensando che potrebbe essere bello per mettere in un timeout fail-safe in modo che, se il "lavoro" sta impiegando troppo tempo, il timer potrebbe riattivare se stessa e riprovare. Stavo pensando a qualcosa di simile a questo:

Sposta il lavoro in una subroutine e creare un delegato:

Private Delegate Sub WorkDelegate()
Private Sub Work()
   '...work...
End Sub

Chiama il lavoro invocando il delegato e quindi utilizzare WaitOne (timeout) sulla IAsyncResult per specificare un timeout:

Private Sub MasterTimer_Elapsed(ByVal sender As Object, ByVal e As System.Timers.ElapsedEventArgs) Handles MasterTimer.Elapsed
    MasterTimer.Enabled = False
    Dim workDel as New WorkDelegate(AddressOf Work)
    Dim result as IAsyncResult = workDel.BeginInvoke
    result.AsyncWaitHandle.WaitOne(CInt(MasterTimer.Interval))
    MasterTimer.Enabled = True
End Sub

Ma, la mia domanda è: Sarebbe questa causa un problema se il lavoro () era davvero da qualche parte bloccato? In che sarebbe reinserire una subroutine che è già in esecuzione? C'è un modo per abortire lavoro () se non ha terminato dopo il timeout? In altre parole, basta cessare l'esecuzione dei lavori () se result.IsCompleted è falso dopo WaitOne?

Non capisco questa roba molto bene così, qualsiasi commento sarebbe molto apprezzato. Forse c'è un modo completamente diverso di avvicinarsi a questo che io non so?

Grazie mille in anticipo!

Vorrei aggiungere una cosa:

Anche se ho intenzione di fare un po 'riscrive come da suggerimenti Hans', avevo già programmato una giornata di prove per cercare di isolare l'origine di questo errore. Finora, si è verificato solo quando si esegue l'applicazione compilata. Ho speso oggi (e un po 'di ieri) cercando di riprodurre il congelamento durante l'esecuzione in modalità di debug in modo che forse avrei potuto aggiungere alcuni punti di interruzione e capire cosa sta succedendo. Finora, il programma non ha congelato in modalità debug. Mi chiedo solo se c'è qualcosa di diverso l'ambiente di debug che potrebbe spiegare questo. Potrebbe essere solo che devo essere "fortunato", ma ho eseguito probabilmente tre volte la durata media di tempo dopo il quale il programma di gelò quando si esegue l'eseguibile ... Ancora una volta, sono abbastanza ignorante, ma c'è qualcosa unico per l'ambiente di debug che potrebbe spiegare questo? Io aggiornare di nuovo se si blocca.

È stato utile?

Soluzione

Questo va male sulla prima riga del codice. La classe System.Timers.Timer è piuttosto icky, non c'è assolutamente alcuna garanzia che chiamata Stop () impedirà un'altra chiamata. Il timer ThreadPool.QueueUserWorkItem utilizza per effettuare la chiamata gestore di eventi trascorso. Se il ThreadPool è occupato questo può finire in coda diverse chiamate, in attesa di ottenere il via libera dal programmatore TP per iniziare a correre. Fermare il timer non impedisce quei thread in attesa di esecuzione. Senza l'utilizzo di una serratura, quei fili farà un passo sulla vicenda male e rovinare il vostro stato di comunicazione.

una cassetta di sicurezza è System.Threading.Timer con un periodo di zero in modo si otterrà solo un callback. Ricaricare il timer con il suo metodo Change ().

La chiamata metodo BeginInvoke () di un delegato e poi il blocco su di esso completamento non ha senso. Basta chiamare Invoke (). si evita di bruciare un altro thread.

Sì, se il metodo di 'Lavoro' non ritorna mai allora avete un problema. Un uno irrisolvibile.

Un sacco di questa miseria potrebbe scomparire se si evita di utilizzare il polling per vedere se c'è qualcosa disponibili sulla porta seriale. Lascia che ti dica che c'è qualcosa di utile da fare. Esso genera l'evento DataReceived, su un filo di thread, ogni volta che c'è almeno un byte nel buffer di ricezione. Utilizzando la sua proprietà WriteTimeout è anche un ottimo modo per evitare di rimanere bloccati quando qualcosa non va con il protocollo di comunicazione o il dispositivo. Dedicare una discussione e facendo il blocco Leggi chiama funziona bene.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top