2012-04-12 17 views
5

Ho riscontrato un problema interessante nell'applicazione C# .Net 4.0 utilizzando la classe SerialPort e ThreadPool.QueueUserWorkItem o Task s..Net Thread vs ThreadPool vs Task per comunicazione SerialPort

Il problema si verifica solo se utilizzo 2 o più SerialPort contemporaneamente. Ogni porta seriale viene eseguito nel proprio filo che creo in 1 di 3 modi:

  1. new Thread(DoSerialCommX)
  2. ThreadPool.QueueUserWorkItem(DoSerialCommX)
  3. new Task(DoSerialCommX, TaskCreationOptions.LongRunning).Start()

per illustrare il problema, ho creato il mio metodo DoSerialCommX a leggere e scrivere sulla porta seriale per sempre in un ciclo. Assomiglia a questo: (Non lo faccio in realtà nel mio vero programma, questo è solo un frammento del mio programma di test che isola e illustra il problema).

private void DoSerialCommX() 
{ 
    SerialPort port = new SerialPort("ComX", 9600); 
    port.Open(); 

    while(true) 
    { 
     //Read and write to serial port 
    } 
} 

Se utilizzo il metodo 2 o 3, la comunicazione seriale si interrompe e ricevo molti timeout di comunicazione. Se uso il metodo 1, tutto è buono. Inoltre, dovrei menzionare questo sembra solo si verifica sui miei PC basati su Intel Atom. I PC desktop sembrano non avere problemi.

So che il pool di thread riutilizza i thread e per impostazione predefinita Task utilizza il pool di thread. E so che il pool di thread intendeva davvero operazioni di breve durata. Ma ho provato ad usare il TaskCreationOptions.LongRunning, che pensavo avrebbe generato un thread dedicato piuttosto che usare il pool di thread, ma ancora non funzionava.

Quindi la domanda: Che cosa rende così speciale Thread in questa situazione? C'è qualcosa di Thread che lo rende più adatto alle operazioni di I/O?

Edit: Le risposte finora sembrano dare per scontato che io sto cercando di utilizzare il ThreadPool o Attività per un processo senza fine. Nella mia vera applicazione questo non è il caso. Sto solo usando un ciclo infinito nel codice qui sopra per illustrare il problema. Ho davvero bisogno di sapere perché Thread funziona e ThreadPool e Task no. Che cosa è tecnicamente diverso da loro che potrebbe causare il singhiozzo della comunicazione seriale?

+0

Suppongo sia una domanda stupida, ma non stai cercando di gestire> = 25 thread, vero? – Jeff

+0

@ JeffN825, no, c'è solo 1 thread per porta seriale e sto usando al massimo 4 porte seriali. – Verax

+0

1 e 3 sono uguali. –

risposta

2

Filosoficamente c'è poca differenza tra 1, 2 e 3 in come si comporta il thread in esecuzione. Condividono tutti la stessa priorità di esecuzione predefinita, a meno che non si esegua l'override - a livello teorico, lo scheduler dei thread utilizza la stessa strategia per programmarli. Si siederanno tutti felici girando per il giro.

ho il sospetto che la più grande differenza tra i metodi è:

  1. costi di infrastruttura (le discussioni, la memoria ecc) filata fino a supporto di thread di # 2 e # 3 ognuno dei quali si contenderanno l'orologio porzione di tempo con la vostra esecuzione ciclo continuo.
  2. costo di cambio contesto thread sull'Atomo meno muscolare. L'Atom ha una cache più piccola, e pipeline di elaborazione più brevi. Più thread in esecuzione = più switch di contesto, più dumping di pipeline (s) e ridotta efficienza della cache delle istruzioni.

Da un punto di vista funzionale, l'utilizzo dei metodi 2 e 3 è alquanto offensivo: l'intenzione è di non uscire mai dal metodo. Queste strategie sono ottimizzate per operazioni atomiche e finite e un'esecuzione alquanto incustodita di operazioni di porta di I/O completamento come rete asincrona, operazioni su disco ecc ... (Forse anche una possibilità per il tuo codice di porta seriale)

Vorrei salta 2 & 3 a meno che non ti interessi l'adattamento all'IO asincrono. Concentrati sul thread: sembra che tu stia desiderando una grana più fine, un controllo prevedibile dell'esecuzione senza il sovraccarico di infrastruttura che Threadpool comporta.

+1

È una porta seriale da 9600 baud! Un personaggio ogni millisecondo. L'UART ha un buffer hardware, il driver ha un buffer. È quasi incredibile che uno di questi due punti potrebbe essere un problema qui. –

+0

Il mio laptop Asus con alimentazione atomica, (!), Funzionerà felicemente con due porte seriali a 115Kbaud senza problemi. Non è l'hardware in generale, (sebbene, ovviamente, la scatola dell'OP possa essere cattiva). –

0

ci sono piccole differenze - che hanno causato i timeout:

  • Utilizzando thread crea esplicitamente un nuovo thread quando Thread.start() è chiamato - e garantisce che il codice viene eseguito quello specifico momento.
  • L'utilizzo di ThreadPool garantisce l'apertura di un thread nel prossimo futuro in base alla logica ThreadPool interna. Poiché il numero di ThreadPool è limitato, è consigliabile utilizzarlo per operazioni (lunghe o infinite) in esecuzione.
  • L'utilizzo dell'attività determinerebbe solo l'esecuzione del codice. O su un altro thread o anche sul thread principale e non si assicura che esso venga eseguito immediatamente o che diverse attività vengano eseguite su diversi thread .

Quindi, se si desidera avviare rapidamente l'attività, utilizzare sempre Thread. Sia Task e ThreadPool hanno alcuni "overhead di infrastruttura" aggiuntivi che potrebbero causare i lievi ritardi che hai notato.

Poiché ThreadPool e l'attività non sono pensati per essere utilizzati quando l'attività non esiste mai, suggerisco di utilizzare Thread.

1

Ho il sospetto che ciò accada PERCHÉ state leggendo/scrivendo da una porta COM. Senza questo fattore, tutti questi devono essere identici perché (se si verifica) sono tutti in esecuzione in una discussione con priorità Normale.

Forse leggere su I/O completion ports e il pool di thread per vedere se questo potrebbe spiegare questo strano comportamento.

+0

Penso che tu abbia esattamente ragione. La porta seriale è un componente chiave di questo problema. Potresti forse approfondire il suggerimento sulla porta di completamento I/O? – Verax

+0

Vedere anche http://hi.baidu.com/jrckkyy/blog/item/401422527c131b070df3e37b.html per ulteriori informazioni su come funzionano le porte di completamento I/O. –

1

C'è qualcosa in comune con il tuo codice, il tuo driver o il tuo hardware che ha messo le tue prestazioni della porta seriale così "al limite" che è sull'orlo del non lavorare tutto il tempo. Non dovrebbe esserci alcun problema nell'usare un thread dedicato o il threadpool, (usando un thread threadpool per bloccare su una porta seriale letta).

Due porte seriali 9600-baud che è possibile eseguire con un abaco, fornendo le perle e fili sono ben oliati.

+0

Puh. Posso facilmente eseguire due porte seriali 9600-baud su un abaco arrugginito. –

+0

Va bene per te. Probabilmente hai un abaco multiwired con hyperBeads. –