/// ----------------------------------------------------------------------------------- /// <summary> /// Initializes a new instance of the <see cref="ParserScheduler"/> class. /// </summary> /// ----------------------------------------------------------------------------------- public ParserScheduler(FdoCache cache, IdleQueue idleQueue) { if (cache == null) { throw new ArgumentNullException("cache"); } Trace.WriteLineIf(m_tracingSwitch.TraceInfo, "ParserScheduler(): CurrentThreadId = " + Win32.GetCurrentThreadId()); m_cache = cache; switch (m_cache.LanguageProject.MorphologicalDataOA.ActiveParser) { case "XAmple": m_parserWorker = new XAmpleParserWorker(cache, HandleTaskUpdate, idleQueue); break; case "HC": m_parserWorker = new HCParserWorker(cache, HandleTaskUpdate, idleQueue); break; default: throw new InvalidOperationException("The language project is set to use an unrecognized parser."); } m_parserWorker.ParseFiler.WordformUpdated += ParseFiler_WordformUpdated; m_thread = new ConsumerThread <ParserPriority, ParserWork>(Work) { IsBackground = true }; ReloadGrammarAndLexicon(); m_thread.Start(); }
/// ----------------------------------------------------------------------------------- /// <summary> /// Initializes a new instance of the <see cref="ParserScheduler"/> class. /// </summary> /// ----------------------------------------------------------------------------------- public ParserScheduler(FdoCache cache, IdleQueue idleQueue, string dataDir) { m_parserWorker = new ParserWorker(cache, HandleTaskUpdate, idleQueue, dataDir); m_parserWorker.ParseFiler.WordformUpdated += ParseFiler_WordformUpdated; m_thread = new ConsumerThread <ParserPriority, ParserWork>(Work); ReloadGrammarAndLexicon(); m_thread.Start(); }
protected override void DisposeManagedResources() { m_thread.Stop(); m_thread.Dispose(); if (m_parserWorker != null) { m_parserWorker.ParseFiler.WordformUpdated -= ParseFiler_WordformUpdated; m_parserWorker.Dispose(); m_parserWorker = null; } if (m_TaskReport != null) { m_TaskReport.Dispose(); m_TaskReport = null; } }
protected override void DisposeManagedResources() { m_thread.Stop(); m_thread.Dispose(); if (m_parserWorker != null) { m_parserWorker.ParseFiler.WordformUpdated -= ParseFiler_WordformUpdated; m_parserWorker.Dispose(); m_parserWorker = null; } if (m_TaskReport != null) { m_TaskReport.Dispose(); m_TaskReport = null; } }
/// ----------------------------------------------------------------------------------- /// <summary> /// Initializes a new instance of the <see cref="ParserScheduler"/> class. /// </summary> /// ----------------------------------------------------------------------------------- public ParserScheduler(FdoCache cache, IdleQueue idleQueue, string dataDir) { m_parserWorker = new ParserWorker(cache, HandleTaskUpdate, idleQueue, dataDir); m_parserWorker.ParseFiler.WordformUpdated += ParseFiler_WordformUpdated; m_thread = new ConsumerThread<ParserPriority, ParserWork>(Work) {IsBackground = true}; ReloadGrammarAndLexicon(); m_thread.Start(); }
private void MainLoop(WaitHandle[] waitEvents, bool bIdle) { try { while (true) { // DebugMsg("parser worker thread loop"); // Look for STOP event or real work int waitIndex = WaitHandle.WaitAny(waitEvents, m_waitTime, false); // handle the STOP event without doing other work if (waitIndex == 0) { try { if (!Monitor.TryEnter(this)) { TraceMsg(lockingSwitch.TraceInfo, ">>>>>>>***** collision locking parser thread A********<<<<<<<<<<<"); Monitor.Enter(this); } if (m_parserWorker != null) { m_parserWorker.Dispose(); m_parserWorker = null; } if (m_sqlConnection != null) { m_sqlConnection.Close(); m_sqlConnection = null; } break; } finally { Monitor.Exit(this); } } // handle the Paused 'state' if (IsPaused) { Thread.Sleep(250); // give it a quarter second to become unpaused continue; // Paused, continue allows checking for Stop event } // not Stopped or Paused, see if the Grammar needs to be updated bool notYetLoaded; try { if (!Monitor.TryEnter(this)) { TraceMsg(lockingSwitch.TraceInfo, ">>>>>>>***** collision locking parser thread B********<<<<<<<<<<<"); Monitor.Enter(this); } notYetLoaded = m_lastGrammarUpdateStamp.Empty; } finally { Monitor.Exit(this); } if (notYetLoaded) { LoadGrammarAndLexicon(NeedsUpdate.GrammarAndLexicon); bIdle = false; } else { NeedsUpdate updateNeeded = GetGrammarOrLexiconNeedsUpdate(); LoadGrammarAndLexicon(updateNeeded); if (updateNeeded != NeedsUpdate.Nothing) bIdle = false; // now there is something to do } // See if none of our previous events have been fired if (waitIndex == WaitHandle.WaitTimeout) { // switch back to lower priority thread, if not already if (Thread.CurrentThread.Priority != ThreadPriority.BelowNormal) { Thread.CurrentThread.Priority = ThreadPriority.BelowNormal; Trace.WriteLineIf(tracingSwitch.TraceInfo, "=======>Scheduler Thread: " + Thread.CurrentThread.ManagedThreadId.ToString() + " setting priority to BelowNormal"); } // still nothing pending... if (!bIdle) { //Trace.WriteLine("MainLoop: Begin Show Idle, WaitHandle.WaitTimeout"); new TaskReport(ParserCoreStrings.ksIdle_, new TaskUpdateEventHandler(this.HandleTaskUpdate)); //Trace.WriteLine("MainLoop: End Show Idle, WaitHandle.WaitTimeout"); bIdle = true; // this will keep us from reporting 'idle' constantly } continue; } // See if Try a Word is running and there are still words in a queue, but we're not parsing a word for Try a Word if (m_fTryAWordDialogRunning && waitIndex == 2) { if (!bIdle) { //Trace.WriteLine("MainLoop: Begin Show Idle, Try A Word"); new TaskReport(ParserCoreStrings.ksIdle_, new TaskUpdateEventHandler(this.HandleTaskUpdate)); //Trace.WriteLine("MainLoop: End Show Idle, Try A Word"); bIdle = true; // this will keep us from reporting 'idle' constantly } continue; } bIdle = false; // turn off idle flag DoWordEvent(waitIndex); } } catch (System.Threading.ThreadInterruptedException) { //m_caughtException = error; } catch (System.Threading.ThreadAbortException) { //m_caughtException = error; } }
/// <summary> /// Executes in two distinct scenarios. /// /// 1. If disposing is true, the method has been called directly /// or indirectly by a user's code via the Dispose method. /// Both managed and unmanaged resources can be disposed. /// /// 2. If disposing is false, the method has been called by the /// runtime from inside the finalizer and you should not reference (access) /// other managed objects, as they already have been garbage collected. /// Only unmanaged resources can be disposed. /// </summary> /// <param name="disposing"></param> /// <remarks> /// If any exceptions are thrown, that is fine. /// If the method is being done in a finalizer, it will be ignored. /// If it is thrown by client code calling Dispose, /// it needs to be handled by fixing the bug. /// /// If subclasses override this method, they should call the base implementation. /// </remarks> private void Dispose(bool disposing) { //Debug.WriteLineIf(!disposing, "****************** " + GetType().Name + " 'disposing' is false. ******************"); //Debug.Assert(disposing, "Don't even think about not disposing this object properly!"); // Must not be run more than once. if (m_isDisposed) return; if (disposing) { // Dispose managed resources here. if (m_consumerThread != null) { //REVIEW: not sure if this is right // if(this.IsPaused) // this.Resume(); // Notify the parser to quit if it's running. See LT-3546 for motivation. if (m_parserWorker != null) { int idThread = m_parserWorker.ThreadId; Trace.WriteLineIf(tracingSwitch.TraceInfo, "ParserScheduler.Dispose(true): m_parserWorker.ThreadId = " + idThread.ToString() + ", m_consumerThread.ManagedThreadId = " + m_consumerThread.ManagedThreadId + ", GetCurrentThreadId() = " + Win32.GetCurrentThreadId().ToString()); if (idThread != 0) { bool fOk; fOk = Win32.PostThreadMessage(idThread, (int)Win32.WinMsgs.WM_USER, (uint)Win32.WinMsgs.WM_QUIT, (uint)idThread); if (!fOk) Trace.WriteLineIf(tracingSwitch.TraceError, "ParserScheduler.Dispose(true): Win32.PostThreadMessage() to stop thread failed!??"); } } // REVIEW DanH (RandyR): Why is is paused only to be resumed? AttemptToPause(); //un-pause if necessary Resume(); //note that this is a polite interruption... it will only stop the thread if it is sleeping //m_consumerThread.Interrupt(); if (m_consumerThread.IsAlive) { m_consumerThread.Priority = ThreadPriority.AboveNormal; // make sure we are normal priority to get chance to run m_consumerThread.Interrupt(); } m_StopEvent.Set(); // ready to stop now, signal STOP event // If the DB is still working, then it will pull the plug on the thread. // I (RandyR) reset the timeout for the DB to be 30 seconds, since some actions took longer than the // previous limit of 10 seconds. // Therefore, I bumped this wait from 10 to 45 seconds. // Even 45 seconds isn't long enough when it is dumping the grammar and lexicon, for larger data sets. if (m_consumerThread.IsAlive == false || m_consumerThread.Join(new TimeSpan(0,0,45))) // wait up to 45 seconds, since the DQ connection mya be waiting for 30 seconds. { // consumer thread exited Trace.WriteLineIf(tracingSwitch.TraceInfo, "==== ParserScheduler thread Successfully shutdown."); } else { Trace.WriteLineIf(tracingSwitch.TraceError, "**** ERROR : ParserScheduler Thread didn't shut down, Aborting."); try { m_consumerThread.Abort(); } catch (ThreadAbortException) { // Eat the ThreadAbortException exception, since it isn't fatal. } finally { if (m_consumerThread.Join(new TimeSpan(0,0,10))== false) // wait up to 10 more seconds { Trace.WriteLineIf(tracingSwitch.TraceError, "**** ERROR : Abort didn't shutdown."); } // Both of these should have been Closed/Disposed & the variables set to null by now, // IF the thread had shut down properly, that is. if (m_sqlConnection != null) { Trace.WriteLineIf(tracingSwitch.TraceError, "Shut down connection by brute force."); m_sqlConnection.Close(); m_sqlConnection.Dispose(); } if (m_parserWorker != null) { Trace.WriteLineIf(tracingSwitch.TraceError, "Disposing Worker bee by brute force."); m_parserWorker.Dispose(); } } } } } // Dispose unmanaged resources here, whether disposing is true or false. m_caughtException = null; m_sqlConnection = null; m_parserWorker = null; m_consumerThread = null; m_lastGrammarUpdateStamp = null; m_server = null; m_database = null; m_LangProject = null; m_isDisposed = true; }
/// ----------------------------------------------------------------------------------- /// <summary> /// Initializes a new instance of the <see cref="ParserScheduler"/> class. /// </summary> /// ----------------------------------------------------------------------------------- public void Init(string server, string database, string LangProject) { DebugMsg("ParserScheduler constructor is being called"); Trace.WriteLineIf(tracingSwitch.TraceInfo, "ParserScheduler(): CurrentThreadId = " + Win32.GetCurrentThreadId().ToString()); m_server = server; m_database = database; m_LangProject = LangProject; m_paused = false; m_sqlConnection = new SqlConnection(GetConnectionString()); m_sqlConnection.Open(); SqlCommand command = m_sqlConnection.CreateCommand(); command.CommandText = "select top 1 ParserParameters from MoMorphData"; XmlDocument doc = new XmlDocument(); doc.LoadXml(((string)command.ExecuteScalar()).Trim()); XmlNode parserNode = doc.SelectSingleNode("/ParserParameters/ActiveParser"); m_parser = parserNode == null ? "XAmple" : parserNode.InnerText; // could use reflection to create the correct parser worker, then this switch statement // would not need to be updated for each parser, probably not a big deal for now switch (m_parser) { case "XAmple": m_parserWorker = new XAmpleParserWorker(m_sqlConnection, m_database, m_LangProject, new TaskUpdateEventHandler(this.HandleTaskUpdate)); break; case "HC": m_parserWorker = new HCParserWorker(m_sqlConnection, m_database, m_LangProject, new TaskUpdateEventHandler(this.HandleTaskUpdate)); break; } m_lastGrammarUpdateStamp = new TimeStamp(); m_fForceGrammarOrLexiconNeedsUpdatingCheck = false; m_StopEvent = new ManualResetEvent(false); m_PauseEvent = new ManualResetEvent(false); m_QueueEvent = new ManualResetEvent(false); m_TryAWordEvent = new ManualResetEvent(false); m_waitTime = new TimeSpan(0, 0, 1); m_lowQueue = new M3ParserWordformQueue(); m_mediumQueue = new M3ParserWordformQueue(); m_highQueue = new M3ParserWordformQueue(); // m_traceQueue = new M3ParserWordformQueue(); m_consumerThread = new Thread(new ThreadStart(this.ConsumerThreadStart)); m_consumerThread.Priority = ThreadPriority.BelowNormal; m_consumerThread.IsBackground = true; // Can't prevent owning app from terminating. m_consumerThread.Name = "Parser scheduler-worker"; m_consumerThread.SetApartmentState(ApartmentState.STA); // do before starting - DH m_consumerThread.CurrentUICulture = System.Threading.Thread.CurrentThread.CurrentUICulture; m_consumerThread.Start(); m_cref = 1; }