[C#] Bästa sättet att avbryta en tråd?

Permalänk
Medlem

[C#] Bästa sättet att avbryta en tråd?

Hej,

Undrar vilket sätt man bör använda för att avbryta en tråd. Finns kanske många sätt men jag kan direkt se att man kan använda Thread.Abort(). Den metoden beskrivs i msdn så här:

Citat:

Raises a ThreadAbortException in the thread on which it is invoked, to begin the process of terminating the thread. Calling this method usually terminates the thread.

Att använda exceptions är väl allmänt känt som ett mindre bra sätt att styra program, jag antar att det har att göra med att det är oftast långsammare och ibland svårare att förstå när man läser koden (vilket iofs inte har någon betydelse i detta fallet)? Det står också att den metoden oftast avbryter tråden. Varför avbryts inte tråden alltid?

Man kan ju också göra följande

private void Run() { while (!abort) { //blabla } } private void Abort() { abort = true; }

Hur skulle ni säga är det bästa sättet att avbryta en tråd, vilket sätt anses "korrekt"?

Permalänk
Hedersmedlem

Det senare anses betydligt snyggare; särskilt om "abort" är en volatile bool. Andra nackdelar med abort är att man inte vet i vilket läge tråden avbröts, vilket till exempel kan leda till att delade resurser (minne, lås och liknande) inte återlämnas som man har tänkt sig.

Se även: http://stackoverflow.com/questions/1559255/whats-wrong-with-u...

Permalänk
Medlem

Förövrigt:
Du ska, precis som du säger, aldrig, aldrig, aldrig, styra ditt program med exceptions!
Exceptions är till för exceptionella saker! Ett fungerande program skall aldrig kasta några exceptions.

Låt t.ex. tråden bara få löpa ut (t.ex. med ditt abort exempel)

Visa signatur

citera!

Permalänk
Medlem

Tackar för hjälpen. Har inte behövt använda mig av lås eller liknande saker tidigare, eller snarare, det trodde jag, insåg precis att man måste ju självklart se till att inte sätta abort till false igen innan tråden har fått löpa ut. Kanske inte är ett lås, men något åt det hållet är det ju.

Skrivet av Dosshell:

Förövrigt:
Du ska, precis som du säger, aldrig, aldrig, aldrig, styra ditt program med exceptions!
Exceptions är till för exceptionella saker! Ett fungerande program skall aldrig kasta några exceptions.

Låt t.ex. tråden bara få löpa ut (t.ex. med ditt abort exempel)

Lite halvt off-topic nu, men borde inte användarfel som felaktig input kasta exceptions?

Permalänk
Hedersmedlem
Skrivet av Goose7:

Lite halvt off-topic nu, men borde inte användarfel som felaktig input kasta exceptions?

Man skulle kunna säga något om att användar är bland det besvärligare man måste kompensera för, men trots detta går det ofta att lösa (i alla fall förutsägbara fel) snyggare.

Permalänk
Medlem
Skrivet av Dosshell:

Förövrigt:
Du ska, precis som du säger, aldrig, aldrig, aldrig, styra ditt program med exceptions!
Exceptions är till för exceptionella saker! Ett fungerande program skall aldrig kasta några exceptions.

Låt t.ex. tråden bara få löpa ut (t.ex. med ditt abort exempel)

Du kan/bör styra med exceptions i vissa sammanhang. T ex vid TimeOut från databas eller liknande. Halvklurigt att inte använda en catch exception.... Eller när en socket kopplar ner. Sunt förnuft är det som gäller.

Visa signatur

Lill-server(2010): SFF NAS Zotac H55ITX-C-E, Lian Li PC-Q08B, Intel Core i3 540
Stor-server(2014): SuperMicro X10SL7-F, 20GB ECC RAM, 4x2TB WD Green, E3-1230v3, 2xIntel Dual Gigabit Nic

Permalänk
Medlem

Jag har börjat använda mig av CancellationToken i System.Threading under NET 4.0.

Kan f.ö rekommendera http://www.albahari.com/threading/ för en bra överblick över trådning i C#.

Jag har inget i med cancellationtoken i prod miljö ännu men det verkar bli något ungeför så här.

Vid startande av trådar:

protected virtual void StartListenerThreads ( ) { Check.Requires<ArgumentNullException> ( Proxies.EndpointCollection != null, "Could not find the collections of endpoints in proxy section in app.config." ); if ( Proxies.EndpointCollection.Count == 0 ) { Log.Info ( "There are no endpoints specified in proxy section in .config file. No threads waiting for data will be running." ); } Parallel.ForEach ( Proxies.EndpointCollection, endpoint => { var uri = new Uri ( endpoint.Uri ); var proxy = Unity.Container.Resolve<IMessageFacade> ( uri.Scheme ); var facade = Unity.Container.Resolve<ICommonFacade> ( endpoint.Facade ); // the listener thread should start listen through its proxy when started.. var thread = new Thread ( ( ) => ListenThroughProxy ( proxy, uri, facade, _cts.Token ) ) { IsBackground = true, Name = uri.AbsoluteUri + "::listener" }; _listeningThreads.Add ( thread ); thread.Start ( ); } ); }

Vid nedstängning av alla trådar

protected override void OnStop ( ) { try { // signal all listener threads to stop.. _cts.Cancel ( false ); Parallel.ForEach ( _listeningThreads, thread => { try { // wait for thread to stop.. if ( thread.Join ( TimeSpan.FromSeconds ( 4 ) ) ) return; Log.Debug ( ( ) => "The thread waiting for data did not stop within {0} seconds after it was signaled to stop. Aborting thread.." .FormatWith ( TimeSpan.FromSeconds ( 4 ).TotalSeconds ) ); // force the thread to abort.. but be prepared for typical thread exceptions.. thread.Abort ( ); } catch ( ThreadStateException ex ) { // the caller attempted to join a thread that is in the ThreadState.Unstarted state.. Log.WarnException ( "Failed to join or abort a thread waiting for data because thread had not been started. This should not happen.", ex ); } catch ( ThreadInterruptedException ) { // calling interrupt when a thread is in the WaitSleepJoin state // will cause a ThreadInterruptedException to be thrown in the target thread.. // if the thread is not in the WaitSleepJoin state, // the exception is not thrown until the thread enters that state. // if the thread never blocks, it could complete without ever being interrupted.. Log.Trace ( ( ) => "Thread was interrupted while in wait state. This can be expected and can be ignored." ); } catch ( Exception ex ) { Log.Warn ( "An unexpected error occured when stopping the service. Because of '{0}'." .FormatWith ( ex.Message ) ); } } ); } finally { Log.Info ( "{0} was stopped at {1} with an uptime of {2}." .FormatWith ( ServiceName, DateTime.Now, DateTime.Now - Started ) ); } }

Permalänk
Medlem
Skrivet av Docker:

Du kan/bör styra med exceptions i vissa sammanhang. T ex vid TimeOut från databas eller liknande. Halvklurigt att inte använda en catch exception.... Eller när en socket kopplar ner. Sunt förnuft är det som gäller.

Jo precis, exceptions är ju bra på att meddela andra delar av koden om fel som man inte kan ignoreras. Det jag menade var att man inte ska kontrollerar programflödet med exceptions, man skall alltså inte programmera så att man vill att ett exception ska kastas när allt fungerar som det ska.

För att citera lite från min favoritbok Code Complete:

Skrivet av Steve McConnell, 2004:

Use exceptions to notify other parts of the program about errors that should not be ignored
...

Throw an exception only for conditions that are truley exceptional
...
Exceptions are used in similar circumstances to assertions-for events that are not just infrequent but for events that should never occur.

Don't use an exception to pass the buck
If an error condition can be handled locally, handle it locally.
...

Avoid throwing exceptions in constructors and deconstructors unless you catch them in the same place.
...

Throw exceptions at the right level of abstraction
...

Tycker det sammanfattar väldigt bra hur man ska använda exceptions.

Och för att svara på din fråga Goose7 om användarfel borde kasta exceptions, hantera dem lokalt utan exceptions.

EDIT: stavfel

Visa signatur

citera!