Un'introduzione al threading in VB.NET

Per comprendere il threading in VB.NET, è utile comprendere alcuni dei concetti di base. Il primo è che il threading è qualcosa che accade perché il sistema operativo lo supporta. Microsoft Windows è un sistema operativo multitasking preventivo. Una parte di Windows denominata Utilità di pianificazione trasferisce il tempo del processore a tutti i programmi in esecuzione. Questi piccoli pezzi di tempo del processore sono chiamati fasce orarie. I programmi non sono responsabili di quanto tempo del processore ottengono, l'utilità di pianificazione è. Poiché questi intervalli di tempo sono così piccoli, si ha l'illusione che il computer stia facendo diverse cose contemporaneamente.

Definizione della discussione

Un thread è un singolo flusso sequenziale di controllo.

Alcuni qualificatori:

  • Un thread è un "percorso di esecuzione" attraverso quel corpo di codice.
  • I thread condividono la memoria, quindi devono cooperare per produrre il risultato corretto.
  • Un thread ha dati specifici del thread come registri, un puntatore di stack e un contatore di programmi.
  • Un processo è un singolo corpo di codice che può avere molti thread, ma ne ha almeno uno e ha un singolo contesto (spazio degli indirizzi).

Questa è roba a livello di assembly, ma è quello che ti viene in mente quando inizi a pensare ai thread.

Multithreading vs. Multiprocessing

Il multithreading non è lo stesso dell'elaborazione parallela multicore, ma il multithreading e il multiprocessing funzionano insieme. La maggior parte dei PC oggi ha processori che hanno almeno due core e le macchine domestiche ordinarie a volte hanno fino a otto core. Ogni core è un processore separato, in grado di eseguire programmi da solo. Si ottiene un aumento delle prestazioni quando il sistema operativo assegna un processo diverso a core diversi. L'uso di più thread e più processori per prestazioni ancora maggiori è chiamato parallelismo a livello di thread.

Molto di ciò che può essere fatto dipende da ciò che il sistema operativo e l'hardware del processore possono fare, non sempre da ciò che puoi fare nel tuo programma e non dovresti aspettarti di essere in grado di utilizzare più thread su tutto. In effetti, potresti non trovare molti problemi che beneficiano di più thread. Quindi, non implementare il multithreading solo perché è lì. Puoi facilmente ridurre le prestazioni del tuo programma se non è un buon candidato per il multithreading. Proprio come esempi, i codec video possono essere i programmi peggiori per il multithread perché i dati sono intrinsecamente seriali. I programmi server che gestiscono le pagine Web potrebbero essere tra i migliori perché i diversi client sono intrinsecamente indipendenti.

Praticare la sicurezza del filo

Il codice multithread richiede spesso una complessa coordinazione dei thread. I bug sottili e difficili da trovare sono comuni perché spesso thread diversi devono condividere gli stessi dati in modo che i dati possano essere modificati da un thread quando un altro non se lo aspetta. Il termine generale per questo problema è "condizioni di gara". In altre parole, i due thread possono entrare in una "gara" per aggiornare gli stessi dati e il risultato può essere diverso a seconda del thread "vince". A titolo di esempio banale, supponiamo che stai codificando un loop:

Se il contatore del loop "I" salta inaspettatamente il numero 7 e va da 6 a 8, ma solo una parte del tempo, avrebbe effetti disastrosi su qualunque cosa stia facendo il loop. Prevenire problemi come questo si chiama sicurezza dei thread. Se il programma necessita del risultato di un'operazione in un'operazione successiva, può essere impossibile codificare processi paralleli o thread per farlo. 

Operazioni base di multithreading

È tempo di mettere in discussione questo discorso precauzionale e scrivere un codice multithreading. Questo articolo utilizza un'applicazione console per semplicità in questo momento. Se si desidera seguire, avviare Visual Studio con un nuovo progetto Applicazione console.

Lo spazio dei nomi principale utilizzato dal multithreading è lo spazio dei nomi System.Threading e la classe Thread crea, avvia e arresta nuovi thread. Nell'esempio seguente, notare che TestMultiThreading è un delegato. Cioè, devi usare il nome di un metodo che può chiamare il metodo Thread.

In questa app, avremmo potuto eseguire il secondo Sottotitolo semplicemente chiamandolo:

Ciò avrebbe eseguito l'intera applicazione in modo seriale. Il primo esempio di codice sopra, tuttavia, dà il via alla subroutine TestMultiThreading e quindi continua.

Un esempio di algoritmo ricorsivo

Ecco un'applicazione multithread che coinvolge il calcolo delle permutazioni di un array usando un algoritmo ricorsivo. Non tutto il codice è mostrato qui. La matrice di caratteri permutata è semplicemente "1", "2", "3", "4" e "5." Ecco la parte pertinente del codice.