From b69a4239cd049cb93e34509c33a6a7ec17b0eb92 Mon Sep 17 00:00:00 2001 From: Zwirbelbart Date: Tue, 28 Apr 2015 03:45:29 +0200 Subject: [PATCH] fixed thread aborting --- src/IrcClient/Channel.cs | 6 +- src/IrcClient/IrcClient.cs | 4 +- src/IrcClient/NonRfcChannel.cs | 7 +- src/IrcConnection/IrcConnection.cs | 206 ++++++++++++----------------- 4 files changed, 95 insertions(+), 128 deletions(-) diff --git a/src/IrcClient/Channel.cs b/src/IrcClient/Channel.cs index 0ad08c1..980003a 100644 --- a/src/IrcClient/Channel.cs +++ b/src/IrcClient/Channel.cs @@ -41,9 +41,9 @@ public class Channel { private string _Name; private string _Key = String.Empty; - private Hashtable _Users = Hashtable.Synchronized(new Hashtable(new CaseInsensitiveHashCodeProvider(), new CaseInsensitiveComparer())); - private Hashtable _Ops = Hashtable.Synchronized(new Hashtable(new CaseInsensitiveHashCodeProvider(), new CaseInsensitiveComparer())); - private Hashtable _Voices = Hashtable.Synchronized(new Hashtable(new CaseInsensitiveHashCodeProvider(), new CaseInsensitiveComparer())); + private Hashtable _Users = Hashtable.Synchronized(new Hashtable(StringComparer.OrdinalIgnoreCase)); + private Hashtable _Ops = Hashtable.Synchronized(new Hashtable(StringComparer.OrdinalIgnoreCase)); + private Hashtable _Voices = Hashtable.Synchronized(new Hashtable(StringComparer.OrdinalIgnoreCase)); private StringCollection _Bans = new StringCollection(); private List _BanExcepts = new List(); private List _InviteExcepts = new List(); diff --git a/src/IrcClient/IrcClient.cs b/src/IrcClient/IrcClient.cs index 3d6b7f1..5a631e8 100644 --- a/src/IrcClient/IrcClient.cs +++ b/src/IrcClient/IrcClient.cs @@ -67,8 +67,8 @@ public class IrcClient : IrcCommands private bool _MotdReceived; private Array _ReplyCodes = Enum.GetValues(typeof(ReplyCode)); private StringCollection _JoinedChannels = new StringCollection(); - private Hashtable _Channels = Hashtable.Synchronized(new Hashtable(new CaseInsensitiveHashCodeProvider(), new CaseInsensitiveComparer())); - private Hashtable _IrcUsers = Hashtable.Synchronized(new Hashtable(new CaseInsensitiveHashCodeProvider(), new CaseInsensitiveComparer())); + private Hashtable _Channels = Hashtable.Synchronized(new Hashtable(StringComparer.OrdinalIgnoreCase)); + private Hashtable _IrcUsers = Hashtable.Synchronized(new Hashtable(StringComparer.OrdinalIgnoreCase)); private List _ChannelList; private Object _ChannelListSyncRoot = new Object(); private AutoResetEvent _ChannelListReceivedEvent; diff --git a/src/IrcClient/NonRfcChannel.cs b/src/IrcClient/NonRfcChannel.cs index 10d94d6..115b5b6 100644 --- a/src/IrcClient/NonRfcChannel.cs +++ b/src/IrcClient/NonRfcChannel.cs @@ -26,6 +26,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +using System; using System.Collections; using System.Collections.Specialized; @@ -37,9 +38,9 @@ namespace Meebey.SmartIrc4net /// public class NonRfcChannel : Channel { - private Hashtable _Owners = Hashtable.Synchronized(new Hashtable(new CaseInsensitiveHashCodeProvider(), new CaseInsensitiveComparer())); - private Hashtable _ChannelAdmins = Hashtable.Synchronized(new Hashtable(new CaseInsensitiveHashCodeProvider(), new CaseInsensitiveComparer())); - private Hashtable _Halfops = Hashtable.Synchronized(new Hashtable(new CaseInsensitiveHashCodeProvider(), new CaseInsensitiveComparer())); + private Hashtable _Owners = Hashtable.Synchronized(new Hashtable(StringComparer.OrdinalIgnoreCase)); + private Hashtable _ChannelAdmins = Hashtable.Synchronized(new Hashtable(StringComparer.OrdinalIgnoreCase)); + private Hashtable _Halfops = Hashtable.Synchronized(new Hashtable(StringComparer.OrdinalIgnoreCase)); /// /// diff --git a/src/IrcConnection/IrcConnection.cs b/src/IrcConnection/IrcConnection.cs index afeaab9..5f75b83 100644 --- a/src/IrcConnection/IrcConnection.cs +++ b/src/IrcConnection/IrcConnection.cs @@ -812,9 +812,9 @@ public void Disconnect() IsDisconnecting = true; - _IdleWorkerThread.Stop(); - _ReadThread.Stop(); - _WriteThread.Stop(); + _IdleWorkerThread.RequestStop(); + _ReadThread.RequestStop(); + _WriteThread.RequestStop(); _TcpClient.Close(); _IsConnected = false; _IsRegistered = false; @@ -1050,17 +1050,65 @@ private void _OnConnectionError(object sender, EventArgs e) } catch (ConnectionException) { } } - + + /// + /// + /// + private abstract class FiniteThread + { + /// + /// + /// + public Thread Thread { get; internal set; } + + /// + /// + /// + public bool IsStopRequested { get; internal set; } + + /// + /// + /// + public string ThreadName { get; internal set; } + + /// + /// + /// + public void RequestStop() + { + IsStopRequested = true; + } + + protected FiniteThread() + { + IsStopRequested = false; + ThreadName = "(unnamed thread)"; + } + + protected abstract void PrepareStart(); + + protected abstract void Worker(); + + /// + /// + /// + public void Start() { + PrepareStart(); + + Thread = new Thread(Worker) { IsBackground = true, Name = ThreadName}; + Thread.Start(); + } + } + /// /// /// - private class ReadThread + private class ReadThread : FiniteThread { #if LOG4NET private static readonly log4net.ILog _Logger = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); #endif private IrcConnection _Connection; - private Thread _Thread; private Queue _Queue = Queue.Synchronized(new Queue()); public AutoResetEvent QueuedEvent; @@ -1079,61 +1127,20 @@ public ReadThread(IrcConnection connection) { _Connection = connection; QueuedEvent = new AutoResetEvent(false); + ThreadName = "ReadThread ("+_Connection.Address+":"+_Connection.Port+")"; } - /// - /// - /// - public void Start() - { - _Thread = new Thread(new ThreadStart(_Worker)); - _Thread.Name = "ReadThread ("+_Connection.Address+":"+_Connection.Port+")"; - _Thread.IsBackground = true; - _Thread.Start(); - } + protected override void PrepareStart() { } - /// - /// - /// - public void Stop() + protected override void Worker() { #if LOG4NET - _Logger.Debug("Stop()"); -#endif - -#if LOG4NET - _Logger.Debug("Stop(): aborting thread..."); -#endif - _Thread.Abort(); - // make sure we close the stream after the thread is gone, else - // the thread will think the connection is broken! -#if LOG4NET - _Logger.Debug("Stop(): joining thread..."); -#endif - _Thread.Join(); - -#if LOG4NET - _Logger.Debug("Stop(): closing reader..."); -#endif - try { - _Connection._Reader.Close(); - } catch (ObjectDisposedException) { - } - - // clean up our receive queue else we continue processing old - // messages when the read thread is restarted! - _Queue.Clear(); - } - - private void _Worker() - { -#if LOG4NET - Logger.Socket.Debug("ReadThread started"); + Logger.Socket.Debug("ReadThread Worker(): starting"); #endif try { string data = ""; try { - while (_Connection.IsConnected && + while (!IsStopRequested && _Connection.IsConnected && ((data = _Connection._Reader.ReadLine()) != null)) { _Queue.Enqueue(data); QueuedEvent.Set(); @@ -1141,6 +1148,15 @@ private void _Worker() Logger.Socket.Debug("received: \""+data+"\""); #endif } +#if LOG4NET + Logger.Socket.Debug("ReadThread Worker(): loop ended"); + Logger.Socket.Debug("ReadThread Worker(): closing reader"); +#endif + _Connection._Reader.Close(); + + // clean up our receive queue else we continue processing old + // messages when the read thread is restarted! + _Queue.Clear(); } catch (IOException e) { #if LOG4NET Logger.Socket.Warn("IOException: "+e.Message); @@ -1155,11 +1171,6 @@ private void _Worker() _Connection.IsConnectionError = true; } } - } catch (ThreadAbortException) { - Thread.ResetAbort(); -#if LOG4NET - Logger.Socket.Debug("ReadThread aborted"); -#endif } catch (Exception ex) { #if LOG4NET Logger.Socket.Error(ex); @@ -1171,10 +1182,9 @@ private void _Worker() /// /// /// - private class WriteThread + private class WriteThread : FiniteThread { private IrcConnection _Connection; - private Thread _Thread; private int _HighCount; private int _AboveMediumCount; private int _MediumCount; @@ -1198,47 +1208,19 @@ public WriteThread(IrcConnection connection) { _Connection = connection; QueuedEvent = new AutoResetEvent(false); + ThreadName = "WriteThread (" + _Connection.Address + ":" + _Connection.Port + ")"; } - /// - /// - /// - public void Start() - { - _Thread = new Thread(new ThreadStart(_Worker)); - _Thread.Name = "WriteThread ("+_Connection.Address+":"+_Connection.Port+")"; - _Thread.IsBackground = true; - _Thread.Start(); - } + protected override void PrepareStart() { } - /// - /// - /// - public void Stop() - { -#if LOG4NET - Logger.Connection.Debug("Stopping WriteThread..."); -#endif - - _Thread.Abort(); - // make sure we close the stream after the thread is gone, else - // the thread will think the connection is broken! - _Thread.Join(); - - try { - _Connection._Writer.Close(); - } catch (ObjectDisposedException) { - } - } - - private void _Worker() + protected override void Worker() { #if LOG4NET - Logger.Socket.Debug("WriteThread started"); + Logger.Socket.Debug("WriteThread Worker(): starting"); #endif try { try { - while (_Connection.IsConnected) { + while (!IsStopRequested && _Connection.IsConnected) { QueuedEvent.WaitOne(); var isBufferEmpty = false; do { @@ -1246,6 +1228,11 @@ private void _Worker() Thread.Sleep(_Connection._SendDelay); } while (!isBufferEmpty); } +#if LOG4NET + Logger.Socket.Debug("WriteThread Worker(): loop ended"); + Logger.Socket.Debug("WriteThread Worker(): closing writer"); +#endif + _Connection._Writer.Close(); } catch (IOException e) { #if LOG4NET Logger.Socket.Warn("IOException: " + e.Message); @@ -1260,11 +1247,6 @@ private void _Worker() _Connection.IsConnectionError = true; } } - } catch (ThreadAbortException) { - Thread.ResetAbort(); -#if LOG4NET - Logger.Socket.Debug("WriteThread aborted"); -#endif } catch (Exception ex) { #if LOG4NET Logger.Socket.Error(ex); @@ -1433,10 +1415,9 @@ private bool _CheckLowBuffer() /// /// /// - private class IdleWorkerThread + private class IdleWorkerThread : FiniteThread { private IrcConnection _Connection; - private Thread _Thread; /// /// @@ -1445,39 +1426,26 @@ private class IdleWorkerThread public IdleWorkerThread(IrcConnection connection) { _Connection = connection; + ThreadName = "IdleWorkerThread ("+_Connection.Address+":"+_Connection.Port+")"; } /// /// /// - public void Start() + protected override void PrepareStart() { DateTime now = DateTime.Now; _Connection._LastPingSent = now; _Connection._LastPongReceived = now; - - _Thread = new Thread(new ThreadStart(_Worker)); - _Thread.Name = "IdleWorkerThread ("+_Connection.Address+":"+_Connection.Port+")"; - _Thread.IsBackground = true; - _Thread.Start(); - } - - /// - /// - /// - public void Stop() - { - _Thread.Abort(); - _Thread.Join(); } - private void _Worker() + protected override void Worker() { #if LOG4NET - Logger.Socket.Debug("IdleWorkerThread started"); + Logger.Socket.Debug("IdleWorkerThread Worker(): starting"); #endif try { - while (_Connection.IsConnected ) { + while (!IsStopRequested && _Connection.IsConnected ) { Thread.Sleep(_Connection._IdleWorkerInterval * 1000); // only send active pings if we are registered @@ -1514,10 +1482,8 @@ private void _Worker() break; } } - } catch (ThreadAbortException) { - Thread.ResetAbort(); #if LOG4NET - Logger.Socket.Debug("IdleWorkerThread aborted"); + Logger.Socket.Debug("IdleWorkerThread Worker(): loop ended"); #endif } catch (Exception ex) { #if LOG4NET