Newsgroup: it.comp.lang.visual-basic
Titolo: [?][.NET] Sospendere e riavviare un Thread

Ciao a tutti!
Non riesco a capire come sia possibile "stoppare" momentaneamente un thread
e farlo proseguire in un secondo momento.
Mi sarei aspettato che l'esempietto che segue (scusate, č in C# :P ma il
concetto non cambia) lo facesse correttamente, ma a quanto pare il Resume()
non sortisce alcun effetto :(
Perchč non riparte l'Execute()???  >:(
Grazie!
using System;
using System.Threading;
namespace thread
{
    public class Class1
    {
        public static void Main()
        {
            ThreadedClass t = new ThreadedClass();
            t.Start();
            Thread.Sleep(1);
            t.Suspend();
            t.Resume();
            Thread.Sleep(1);
            t.Abort();
        }
    }
    public class ThreadedClass
    {
        private Thread oThread;
        public ThreadedClass()
        {
            oThread = new Thread(new ThreadStart(this.Execute));
        }
        public void Start()
        {
            oThread.Start();
        }
        public void Abort()
        {
            oThread.Abort();
            oThread.Join();
        }
        public void Suspend()
        {
            oThread.Suspend();
        }
        public void Resume()
        {
            oThread.Resume();
        }
        private void Execute()
        {
            do
            {
                Console.WriteLine(DateTime.Now.ToString() + " - Executing");
            } while (true);
        }
    }
}
--
Math Parser : 
http://www.neodatatype.net
Sito Comune : 
http://www.it-lang-vb.net

Stoppando il tread per 1 millisecondo sarà dura tu riesca a discriminare il
suspend e il relativo resume, sopratutto se nella writeline utilizzi il
secondo come risoluzione.
Quindi prova a stampare i ticks e incrementa il tempo di stop almeno sopra
il tick di sistema.
HTH
-- 
Corrado Cavalli [Microsoft MVP]
UGIdotNET - 
http://www.ugidotnet.org

Perchè non riparte l'Execute()???  >:(
Probabilmente funziona, e' che con una Sleep di 1 ms non e' che si
veda molto bene.
Ho modificato il tuo esempio aggiungendo delle sleep piu' sostanziose
(10 secondi sono sicuramente meglio apprezzabili ad occhio che non 1
millisecondo) e tagliando un po' di codice inutile (per questo
esempio) sulla ThreadedClass.
<codice>
using System;
using System.Threading;
namespace thread
{
	public class Class1
	{
		public static void Main()
		{
			ThreadedClass tc = new ThreadedClass();
			Thread t = 
			   new Thread(new ThreadStart(tc.Execute));
			t.Start();
			Thread.Sleep(1);
			t.Suspend();
			Thread.Sleep(10000);
			t.Resume();
			Thread.Sleep(1);
			Thread.Sleep(10000);
			t.Abort();
		}
	}
	public class ThreadedClass
	{
		public ThreadedClass()
		{
 
		}
		public void Execute()
		{
			do
			{
				Console.WriteLine(
				    DateTime.Now.ToString() + 
					" - Executing");
			} while (true);
		}
	}
}
</codice>
-- 
ciao, hal

 veda molto bene.
Ripropongo l'esempio, e attenzione al trucco, che la mano è più veloce
dell'occhio.
Se lascio tutto così comè si incarta tutto e si blocca sul Suspend().
Se tolgo la riga "BEFORE RESUME" tutto funziona a meraviglia.
Dato che se fermo il thread è per farci qualcosa nel mezzo, tutto questo non
mi sembra molto affidabile.
public static void Main()
{
    ThreadedClass t = new ThreadedClass();
    t.Start();
    Thread.Sleep(1);
    t.Suspend();
    Console.WriteLine("--BEFORE RESUME--");
    t.Resume();
    Console.WriteLine("--AFTER RESUME--");
    Thread.Sleep(1);
    t.Abort();
    Console.WriteLine("--END--");
    Thread.Sleep(10000);


 secondo come risoluzione.
Hai ragione, infatti quello che ho postato funziona :)
Però guarda un po' la mia risposta a hal1961.
Ciao


dell'occhio.
La mano è più veloce ma il fatto che la classe Console non sia thread-safe
sia l'occhio che la mano non l'hanno considerato...
Se infatti modifichi il codice evitando l'accesso dai due threads tutto
funziona correttamente.
Visto che siamo in un NG di VB ritengo corretto postare il codice VB affichè
altri possano partecipare alla discussione.
HTH
-- 
Corrado Cavalli [Microsoft MVP]
UGIdotNET - 
http://www.ugidotnet.org
L'esempio riportato salva i ticks nel file C:\Test.txt
 t.Start()
      Thread.Sleep(400)
      Console.WriteLine("suspend")
      t.Suspend()
      Console.WriteLine("Before resume")
      t.Resume()
      Console.WriteLine("After resume")
      Console.WriteLine("abort")
      Thread.Sleep(1)
      t.Abort()
      MessageBox.Show("ok")
Public Class ThreadedClass
   Private oThread As Thread
   Private mFile As New System.IO.StreamWriter("c:\test.txt")
   Public Sub New()
      oThread = New Thread(AddressOf Execute)
   End Sub
   Public Sub Start()
      oThread.Start()
   End Sub
   Public Sub Abort()
      mFile.Close()
      oThread.Abort()
      oThread.Join()
   End Sub
   Public Sub Suspend()
      oThread.Suspend()
   End Sub
   Public Sub [Resume]()
      oThread.Resume()
   End Sub
   Private Sub Execute()
      While True
         mFile.WriteLine(DateTime.Now.Ticks.ToString)
      End While
   End Sub
End Class

mi sembra molto affidabile.
Se devo essere sincero, a me sembra non affidabile il codice cosi'
come e' scritto. Si stanno usando tecniche che in java sono state
sconsigliate da tempo. E' molto pericoloso forzare le pause e le
terminazioni dei thread da un altro thread, mentre e' piu' sicuro
"chiedere" al thread di sospendersi e/o di fermarsi.
Anche si si tratta di un codice di prova, tra l'altro, manca la
gestione degli errori relativa allo stato del thread: non e' detto, ad
esempio, che quando si va a riesumare un thread questo sia ancora
vivo.
Inoltre la Sleep di un solo millisecondo puo' essere troppo poco per
dare tempo ad un sistema lento come .net di far partire il secondo
thread (ricordati che non stai scrivendo codice C++).
Se lo modifichi cosi' allora funziona (ho mantenuto il codice di
delega in ThreadedClass, anche se non mi piace gran che).
<codice>
using System;
using System.Threading;
namespace thread
{
	public class Class1
	{
		public static void Main()
		{
 
Thread.CurrentThread.Name
 = "Main";
			ThreadedClass t = new ThreadedClass();
			Console.WriteLine(
Thread.CurrentThread.Name
 +
" --BEFORE START--");
			t.Start();
			Thread.Sleep(10);
			t.Suspend();
			Console.WriteLine(
Thread.CurrentThread.Name
 +
" --BEFORE RESUME--");
			t.Resume();
			Console.WriteLine(
Thread.CurrentThread.Name
 +
" --AFTER RESUME--");
			Thread.Sleep(1);
			t.Abort();
			Console.WriteLine(
Thread.CurrentThread.Name
 +
" --END--");
			Thread.Sleep(10000);
		}
	}
	public class ThreadedClass
	{
		private Thread oThread;
		private bool suspended = false;
		public ThreadedClass()
		{
			oThread = new Thread(new
ThreadStart(this.Execute));
			oThread.Name = "ThreadedClass";
		}
		public void Start()
		{
			oThread.Start();
		}
		public void Abort()
		{
			suspended = true;
			oThread.Abort();
			oThread.Join();
		}
		public void Suspend()
		{
			suspended = true;
			try
			{
				oThread.Suspend();
			}
			catch(System.Threading.ThreadStateException e)
			{
				Console.WriteLine(e.StackTrace);
			}
		}
		public void Resume()
		{
			suspended = false;
			try
			{
				oThread.Resume();
			}
			catch(System.Threading.ThreadStateException e)
			{
				Console.WriteLine(e.StackTrace);
			}
		}
		private void Execute()
		{
			do
			{
				Console.WriteLine(
 
Thread.CurrentThread.Name
 + 
					" - " +
DateTime.Now.ToString() + " - Executing");
				Thread.Sleep(1);
			} while (!suspended);
		}
	}
}
</codice>
-- 
ciao, hal

 delega in ThreadedClass, anche se non mi piace gran che).
Mi spieghi perchè così funziona?
Cosa c'è di così importante che mi sfugge?
E tu come gestiresti il problema?
Il mio era solo un esempio, dato che non ho idea di come funzioni (o
dovrebbe funzionare) la cosa sono accette anche soluioni differenti.
Ciao, grazie


 funziona correttamente.
Ancora non capisco perchč cosě debba andare.
Qual č la differenza che non noto?
Provo a spiegare meglio io mio problema perchč forse ci stiamo infognando.
Ho la classe A che usa la classe B (quella con la procedura "threaded").
Ora, A deve poter far partire B.Metodo() in un thread separato, A deve poter
fermare B in qualunque momento, fare le sue cose e poi decidere di farlo
ripartire oppure di fermarlo definitivamente.
Considerando che anche B puň decidere di avere finito il suo compito e
quindi fermare il thread.
Ho visto che si parla anche della classe Monitor anche perchč sembra che
fare i Suspend() e Resume() non č sicuro (lo dice la guida).
Puň essere utile al mio scopo?
Come?
Ciao, grazie ancora


E tu come gestiresti il problema?
Non sono sicuro di aver inquadrato bene la tua domanda, ma credo che
il problema sia, nel caso del codice di esempio, l'uscita dal loop.
Se togli il commento da Thread.Sleep() la v.m. non riesce a terminare
il thread perche' questo non cede mai il controllo: se ci pensi cio'
ha anche un senso (.net o altro linguaggio, il concetto e' lo stesso).
La Sleep ti permette di lasciare lo spazio ad altri eventi ed ecco che
un flag, che ti faccia sapere che il thread corrente deve cessare, si
rivela utile per rilasciare debitamente le risorse, decidendo tu il
come e quando.
<codice>
private void Execute()
{
	do
	{
		Console.WriteLine(
 
Thread.CurrentThread.Name
 + 
			" + DateTime.Now.ToString() + " - Executing");
		/* se la riga di sotto e' commentata allora l'app 
			non termina 
		*/
		// Thread.Sleep(1);
	} while (true);	
}
</codice>
Anzi, mi scuso con i vbisti, dato che questo ng e' di vb, sostituisco
con codice vb:
<codice>
Private Sub Execute()
	Do
		Console.WriteLine(
 
Thread.CurrentThread.Name
 & _ 
			" & DateTime.Now.ToString() & " - Executing")
		' se la riga di sotto e' commentata allora l'app 
		'	non termina 
		' Thread.Sleep(1)
	While (True)
End Sub
</codice>
-- 
ciao, hal

 quello che eventualmente ci sia da rilasciare.
Ok, ma io ho provato in vari modi e quando richiamavo la Resume() lui finiva
la procedura (che conteneca la resume) e poi basta.
Boh.
Ciao


> Qual č la differenza che non noto?
Che stai usando la classe Console sia dal main thread che dal thread
secondario, elimina le chiamate alla classe console e vedrai che tutto gira.
Visto che l'output della classe Console all'interno di VS viene
redirezionato nella Debug window e che storicamente i controlli windows non
sono thread-safe mi viene da pensare che il problema stia proprio lě,
infatti eliminado le chiamate il tutto funziona.


la procedura (che conteneca la resume) e poi basta.
Forse non gli lasciavi il tempo di eseguirsi. Mi rifaccio al codice
postato nel tuo primo messaggio: se metti 10 ms invece di 1 allora
il programma da un output sulla console, per lo meno lanciando l'exe
sulla riga di comando.
-- 
ciao, hal