source: trunk/CrypPlugins/WorkspaceManager/Execution/ExecutionEngine.cs @ 2683

Last change on this file since 2683 was 2683, checked in by kopal, 11 years ago

ExecutionEngine now "consumes" input data after executing a plugin

File size: 26.4 KB
RevLine 
[1449]1/*                             
2   Copyright 2010 Nils Kopal, Viktor M.
3
4   Licensed under the Apache License, Version 2.0 (the "License");
5   you may not use this file except in compliance with the License.
6   You may obtain a copy of the License at
7
8       http://www.apache.org/licenses/LICENSE-2.0
9
10   Unless required by applicable law or agreed to in writing, software
11   distributed under the License is distributed on an "AS IS" BASIS,
12   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   See the License for the specific language governing permissions and
14   limitations under the License.
15*/
16
17using System;
18using System.Collections.Generic;
19using System.Linq;
20using System.Text;
21
22using WorkspaceManager.Model;
23using System.Threading;
24using System.Collections;
25using Cryptool.PluginBase;
26using System.Reflection;
[1590]27using Gears4Net;
[1607]28using System.Windows.Threading;
[1700]29using System.Runtime.Remoting.Contexts;
[1929]30using System.IO;
31using System.Diagnostics;
[1449]32
33namespace WorkspaceManager.Execution
34{
35    /// <summary>
36    /// Engine to execute a model of the WorkspaceManager
[1617]37    /// This class needs a WorkspaceManager to be instantiated
38    /// To run an execution process it also needs a WorkspaceModel
39    ///
40    /// This class uses Gears4Net to execute the plugins
[1449]41    /// </summary>
42    public class ExecutionEngine
43    {
[1471]44        private WorkspaceManager WorkspaceManagerEditor;
[1884]45        private Scheduler scheduler;
[1592]46        private WorkspaceModel workspaceModel;
[1846]47        private volatile bool isRunning = false;
[1977]48        private BenchmarkProtocol BenchmarkProtocol = null;
[1627]49
[1929]50        public volatile int ExecutedPluginsCounter = 0;
51        public bool BenchmarkPlugins = false;
52        public int GuiUpdateInterval = 0;
53        public int SleepTime = 0;
54        public int ThreadPriority = 0;
[1627]55
[1449]56        /// <summary>
57        /// Creates a new ExecutionEngine
58        /// </summary>
59        /// <param name="workspaceManagerEditor"></param>
[1471]60        public ExecutionEngine(WorkspaceManager workspaceManagerEditor)
[1449]61        {
62            WorkspaceManagerEditor = workspaceManagerEditor;
63        }
64
65        /// <summary>
66        /// Is this ExecutionEngine running?
67        /// </summary>
68        public bool IsRunning
69        {
[1846]70            get{return this.isRunning;}
71            private set{this.isRunning = value;}
[1449]72        }
73
74        /// <summary>
[1617]75        /// Execute the given Model
[1449]76        /// </summary>
77        /// <param name="workspaceModel"></param>
[1884]78        public void Execute(WorkspaceModel workspaceModel, int amountThreads)
[1449]79        {
80            if (!IsRunning)
81            {
82                IsRunning = true;
[1777]83                this.workspaceModel = workspaceModel;
[1803]84
[1884]85                if (amountThreads <= 0)
[1866]86                {
[1884]87                    amountThreads = 1;
[1866]88                }
89
[1884]90                scheduler = new WorkspaceManagerScheduler("WorkspaceManagerScheduler", amountThreads,this);
[1700]91               
[1617]92                //We have to reset all states of PluginModels, ConnectorModels and ConnectionModels:
[1449]93                workspaceModel.resetStates();
[1617]94
95                //The UpdateGuiProtocol is a kind of "daemon" which will update the view elements if necessary
[1884]96                UpdateGuiProtocol updateGuiProtocol = new UpdateGuiProtocol(scheduler, workspaceModel, this);
97                scheduler.AddProtocol(updateGuiProtocol);
[1607]98                updateGuiProtocol.Start();
99
[1637]100                //The BenchmarkProtocl counts the amount of executed plugins per seconds and writes this to debug
101                if (this.BenchmarkPlugins)
102                {
[1929]103                    BenchmarkProtocol = new BenchmarkProtocol(scheduler, this.workspaceModel, this);
104                    scheduler.AddProtocol(BenchmarkProtocol);
105                    BenchmarkProtocol.Start();
[1637]106                }
107
[1617]108                //Here we create for each PluginModel an own PluginProtocol
109                //By using round-robin we give each protocol to another scheduler to gain
110                //a good average load balancing of the schedulers
[1684]111                //we also initalize each plugin
[1812]112                //It is possible that a plugin is also a PluginProtocol
[1929]113                //if that is true we do not create a new one but use the plugin instead the created one               
[1449]114                foreach (PluginModel pluginModel in workspaceModel.AllPluginModels)
115                {
[1884]116                    PluginProtocol pluginProtocol = new PluginProtocol(scheduler, pluginModel, this);
[1929]117                    MessageExecution message = new MessageExecution();
118                    message.PluginModel = pluginModel;
119                    pluginModel.MessageExecution = message;
120
[1812]121                    pluginModel.Plugin.PreExecution();                   
[1591]122                    pluginModel.PluginProtocol = pluginProtocol;
[1884]123                    scheduler.AddProtocol(pluginProtocol);
[1812]124
125                    if (pluginProtocol.Status == ProtocolStatus.Created || pluginProtocol.Status == ProtocolStatus.Terminated)
126                    {
127                        pluginProtocol.Start();
128                    }
[1929]129                 
[1680]130                    if (pluginModel.Startable)
131                    {
[1929]132                        pluginProtocol.BroadcastMessage(pluginModel.MessageExecution);
[1680]133                    }
[1449]134                }
[1700]135
[1884]136                ((WorkspaceManagerScheduler)scheduler).startScheduling();
137               
[1449]138            }
[1590]139        }     
140     
[1449]141        /// <summary>
[1617]142        /// Stop the execution process:
143        /// calls shutdown on all schedulers + calls stop() on each plugin
[1449]144        /// </summary>
145        public void Stop()
146        {
[1977]147           
148            //First stop alle plugins
149            foreach (PluginModel pluginModel in workspaceModel.AllPluginModels)
[1684]150            {
[1977]151                pluginModel.Plugin.Stop();                   
152            }
[1684]153
[1977]154            IsRunning = false;
155            //Secondly stop all Gears4Net Schedulers
156            scheduler.Shutdown();
[1929]157
[1977]158            //call all PostExecution methods of all plugins
159            foreach (PluginModel pluginModel in workspaceModel.AllPluginModels)
160            {
161                pluginModel.Plugin.PostExecution();
162            }
[1929]163
[1977]164            //remove the plugin protocol of each plugin model
165            foreach (PluginModel pluginModel in workspaceModel.AllPluginModels)
[1929]166            {
[1977]167                pluginModel.PluginProtocol = null;
[1929]168            }
[1977]169
170            this.WorkspaceManagerEditor = null;
171            this.workspaceModel = null;
172         
[1449]173        }
174
175        /// <summary>
176        /// Pause the execution
177        /// </summary>
178        public void Pause()
179        {
180            //not implemented yet
181        }
182
183        /// <summary>
184        /// Use the logger of the WorkspaceManagerEditor
185        /// </summary>
186        /// <param name="message"></param>
187        /// <param name="level"></param>
[1590]188        public void GuiLogMessage(string message, NotificationLevel level)
[1929]189        {
190            if (WorkspaceManagerEditor != null)
191            {
192                WorkspaceManagerEditor.GuiLogMessage(message, level);
193            }
[1884]194        }
[1590]195    }
[1637]196 
[1590]197    /// <summary>
198    /// Message send to scheduler for a Plugin to trigger the Execution
199    /// </summary>
200    public class MessageExecution : MessageBase
201    {
202        public PluginModel PluginModel;
203    }
204
205    /// <summary>
[1607]206    /// A Protocol for updating the GUI in time intervals
207    /// </summary>
208    public class UpdateGuiProtocol : ProtocolBase
209    {
210        private WorkspaceModel workspaceModel;
[1929]211        private ExecutionEngine executionEngine;
[1607]212
213        /// <summary>
214        /// Create a new protocol. Each protocol requires a scheduler which provides
215        /// a thread for execution.
216        /// </summary>
217        /// <param name="scheduler"></param>
218        public UpdateGuiProtocol(Scheduler scheduler, WorkspaceModel workspaceModel, ExecutionEngine executionEngine)
219            : base(scheduler)
220        {
221            this.workspaceModel = workspaceModel;
[1627]222            this.executionEngine = executionEngine;           
[1607]223        }
[1929]224       
[1607]225        /// <summary>
226        /// The main function of the protocol
227        /// </summary>
228        /// <param name="stateMachine"></param>
229        /// <returns></returns>
230        public override System.Collections.Generic.IEnumerator<ReceiverBase> Execute(AbstractStateMachine stateMachine)
[1929]231        {           
232            yield return new IntervalReceiver(this.executionEngine.GuiUpdateInterval,this.executionEngine.GuiUpdateInterval, HandleUpdateGui);
[1607]233        }
234
235        /// <summary>
236        /// Handler function for a message.
237        /// This handler must not block, because it executes inside the thread of the scheduler.
238        /// </summary>
239        /// <param name="msg"></param>
240        private void HandleUpdateGui()
241        {
242            //Get the gui Thread
243            this.workspaceModel.WorkspaceManagerEditor.Presentation.Dispatcher.Invoke(DispatcherPriority.Normal, (SendOrPostCallback)delegate
244            {
[1884]245                List<PluginModel> pluginModels = workspaceModel.AllPluginModels;
246                foreach (PluginModel pluginModel in pluginModels)
[1607]247                {
248                    if (pluginModel.GuiNeedsUpdate)
249                    {
250                        pluginModel.GuiNeedsUpdate = false;
251                        pluginModel.paint();
252                        if (pluginModel.UpdateableView != null)
253                        {
254                            pluginModel.UpdateableView.update();
255                        }
256                    }
257                }
[1884]258                List<ConnectionModel> connectionModels = workspaceModel.AllConnectionModels;
259                foreach (ConnectionModel connectionModel in connectionModels)
[1620]260                {
261                    if (connectionModel.GuiNeedsUpdate)
262                    {
263                        if (connectionModel.UpdateableView != null)
264                        {
265                            connectionModel.UpdateableView.update();
266                        }
267                    }
268                }
[1607]269            }
270            , null);
[1929]271
[1607]272        }
273    }
[1680]274   
[1607]275    /// <summary>
[1680]276    /// A Protocol for benchmarking
[1608]277    /// </summary>
[1637]278    public class BenchmarkProtocol : ProtocolBase
279    {
280        private WorkspaceModel workspaceModel;
281        private ExecutionEngine executionEngine;
[1977]282     
[1637]283        /// <summary>
284        /// Create a new protocol. Each protocol requires a scheduler which provides
285        /// a thread for execution.
286        /// </summary>
287        /// <param name="scheduler"></param>
288        public BenchmarkProtocol(Scheduler scheduler, WorkspaceModel workspaceModel, ExecutionEngine executionEngine)
289            : base(scheduler)
290        {
291            this.workspaceModel = workspaceModel;
[1977]292            this.executionEngine = executionEngine;         
[1637]293        }
294
295        /// <summary>
296        /// The main function of the protocol
297        /// </summary>
298        /// <param name="stateMachine"></param>
299        /// <returns></returns>
300        public override System.Collections.Generic.IEnumerator<ReceiverBase> Execute(AbstractStateMachine stateMachine)
301        {
[1929]302            yield return new IntervalReceiver(1000,1000, HandleBenchmark);           
[1637]303        }
304
305        /// <summary>
306        /// Handler function for a message.
307        /// This handler must not block, because it executes inside the thread of the scheduler.
308        /// </summary>
309        /// <param name="msg"></param>
310        private void HandleBenchmark()
311        {
[1929]312            StringBuilder sb = new StringBuilder();
313            sb.Append("Executing at about ");
314            sb.Append(this.executionEngine.ExecutedPluginsCounter); 
315            sb.Append(" Plugins/s");
316
[1977]317            this.workspaceModel.WorkspaceManagerEditor.GuiLogMessage(sb.ToString(), NotificationLevel.Debug);         
[1637]318            this.executionEngine.ExecutedPluginsCounter = 0;
[1977]319        }       
[1637]320    }
321
322    /// <summary>
[1590]323    /// A Protocol for a PluginModel
324    /// </summary>
325    public class PluginProtocol : ProtocolBase
[1780]326    {       
[1700]327        public PluginModel PluginModel;
[1590]328        private ExecutionEngine executionEngine;
329
330        /// <summary>
331        /// Create a new protocol. Each protocol requires a scheduler which provides
332        /// a thread for execution.
333        /// </summary>
334        /// <param name="scheduler"></param>
335        public PluginProtocol(Scheduler scheduler, PluginModel pluginModel,ExecutionEngine executionEngine)
336            : base(scheduler)
[1449]337        {
[1700]338            this.PluginModel = pluginModel;
[1590]339            this.executionEngine = executionEngine;
[1929]340        }       
[1449]341
342        /// <summary>
[1812]343        ///
344        /// </summary>
345        /// <param name="scheduler"></param>
346        /// <param name="pluginModel"></param>
347        /// <param name="executionEngine"></param>
348        public void setExecutionEngineSettings(Scheduler scheduler, PluginModel pluginModel, ExecutionEngine executionEngine)
349        {
350            this.Scheduler = scheduler;
351            this.PluginModel = pluginModel;
352            this.executionEngine = executionEngine;
353        }
354
355
356        /// <summary>
[1680]357        /// The main function of the protocol     
[1449]358        /// </summary>
[1590]359        /// <param name="stateMachine"></param>
360        /// <returns></returns>
361        public override System.Collections.Generic.IEnumerator<ReceiverBase> Execute(AbstractStateMachine stateMachine)
[1929]362        {           
363            yield return new PersistentReceiver(Receive<MessageExecution>(this.Filter, HandleExecute));               
[1449]364        }
365
366        /// <summary>
[1876]367        /// Filter that checks wether the Plugin fits to the internal Plugin reference of this PluginProtocl
368        /// </summary>
369        /// <param name="msg"></param>
370        /// <returns></returns>
371        private bool Filter(MessageExecution msg)
372        {
373            if (msg.PluginModel != this.PluginModel)
374            {
375                return false;
376            }
377            return true;
378        }
379        /// <summary>
[1805]380        /// Handle an execution of a plugin
[1449]381        /// </summary>
[1590]382        /// <param name="msg"></param>
[1637]383        private void HandleExecute(MessageExecution msg)
[1449]384        {
[1884]385            // ################
[1805]386            // 1. Check if Plugin may Execute
[1884]387            // ################
[1805]388
[1884]389            if (!msg.PluginModel.WorkspaceModel.WorkspaceManagerEditor.isExecuting())
[1776]390            {
[1805]391                return;
[1776]392            }
393
[1884]394            //Check if all necessary inputs are set
395            List<ConnectorModel> inputConnectors = msg.PluginModel.InputConnectors;
396            foreach (ConnectorModel connectorModel in inputConnectors)
[1806]397            {
[1884]398                if (!connectorModel.IControl &&
399                    (connectorModel.IsMandatory || connectorModel.InputConnections.Count > 0) && !connectorModel.HasData)
400                {
401                    return;
402                }
[1806]403            }
[1805]404
[1884]405            //Check if all outputs are free
406            List<ConnectorModel> outputConnectors = msg.PluginModel.OutputConnectors;
407            foreach (ConnectorModel connectorModel in outputConnectors)
[1776]408            {
[1884]409                if (!connectorModel.IControl)
[1803]410                {
[1884]411                    List<ConnectionModel> outputConnections = connectorModel.OutputConnections;
412                    foreach (ConnectionModel connectionModel in outputConnections)
[1805]413                    {
[1884]414                        if (connectionModel.To.HasData)
415                        {
416                            return;
417                        }
[1805]418                    }
[1803]419                }
420            }
421
[1884]422            // ################
423            //2. Fill all Inputs of the plugin, if this fails, stop executing the plugin
424            // ################
425
[1805]426            //Fill the plugins inputs with data
[1882]427            foreach (ConnectorModel connectorModel in inputConnectors)
[1776]428            {
[1805]429                try
[1776]430                {
[1929]431                    if (connectorModel.HasData && connectorModel.Data != null)
[1776]432                    {
[1805]433                        if (connectorModel.IsDynamic)
434                        {
[2059]435                       
436                            if(connectorModel.method == null)
437                            {
438                                connectorModel.method = PluginModel.Plugin.GetType().GetMethod(connectorModel.DynamicSetterName);
439                            }
440                            connectorModel.method.Invoke(PluginModel.Plugin, new object[] { connectorModel.PropertyName, connectorModel.Data });
[1805]441                        }
442                        else
443                        {
[2059]444                            if (connectorModel.property == null)
445                            {
446                                connectorModel.property = PluginModel.Plugin.GetType().GetProperty(connectorModel.PropertyName);
447                            }
448                            connectorModel.property.SetValue(PluginModel.Plugin, connectorModel.Data, null);
[1805]449                        }
[1769]450                    }
[1590]451                }
[1805]452                catch (Exception ex)
453                {
[1806]454                    this.PluginModel.WorkspaceModel.WorkspaceManagerEditor.GuiLogMessage("An error occured while setting value of connector \"" + connectorModel.Name + "\" of \"" + PluginModel.Name + "\": " + ex.Message, NotificationLevel.Error);
[1805]455                    this.PluginModel.State = PluginModelState.Error;
456                    this.PluginModel.GuiNeedsUpdate = true;
[1884]457                    return;
[1805]458                }
[1802]459            }
[1805]460
[1884]461            // ################
462            //3. Execute the Plugin -> call the IPlugin.Execute()
463            // ################
[1812]464
[1884]465            try
[1805]466            {
[1884]467                PluginModel.Plugin.Execute();
[1805]468            }
[1884]469            catch (Exception ex)
[2152]470            {       
471                this.PluginModel.WorkspaceModel.WorkspaceManagerEditor.GuiLogMessage("An error occured while executing  \"" + PluginModel.Name + "\": " + ex.Message, NotificationLevel.Error);
472                this.PluginModel.State = PluginModelState.Error;
473                this.PluginModel.GuiNeedsUpdate = true;
474                return;               
[1884]475            }
[1805]476
[1884]477            // ################
478            //4. Count for the benchmark
479            // ################
480
481            if (this.executionEngine.BenchmarkPlugins)
[1805]482            {
[1929]483                this.executionEngine.ExecutedPluginsCounter++;               
[1805]484            }
485
[1884]486            // ################
[2683]487            //5. "Consume" all inputs
[1884]488            // ################
489
[2683]490            foreach (ConnectorModel connectorModel in inputConnectors)
491            {
492                try
493                {
494                    if (connectorModel.HasData && connectorModel.Data != null)
495                    {
496                        connectorModel.HasData = false;
497                        connectorModel.Data = null;
498                    }
499                }
500                catch (Exception ex)
501                {
502                    this.PluginModel.WorkspaceModel.WorkspaceManagerEditor.GuiLogMessage("An error occured while 'consuming' value of connector \"" + connectorModel.Name + "\" of \"" + PluginModel.Name + "\": " + ex.Message, NotificationLevel.Error);
503                    this.PluginModel.State = PluginModelState.Error;
504                    this.PluginModel.GuiNeedsUpdate = true;
505                    return;
506                }
507            }
508           
509            // ################
510            //6. If the user wants to, sleep some time
511            // ################
512
[1884]513            if (this.executionEngine.SleepTime > 0)
[1805]514            {
[1884]515                Thread.Sleep(this.executionEngine.SleepTime);
[1805]516            }
[1884]517        }       
518
[1812]519        /// <summary>
520        ///
521        /// </summary>
522        public ExecutionEngine ExecutionEngine
523        {
524            get { return this.executionEngine; }           
525        }
[1449]526    }
[1700]527
[1755]528    /// <summary>
[1802]529    /// Gears4Net Scheduler
[1755]530    /// </summary>
[1700]531    public class WorkspaceManagerScheduler : Scheduler
532    {
533        private System.Threading.AutoResetEvent wakeup = new System.Threading.AutoResetEvent(false);
534        private bool shutdown = false;
[1884]535        private Thread[] threads;
[1977]536        private volatile int runningThreads = 0;
537
[1884]538        public ExecutionEngine executionEngine = null;         
[1700]539
[1884]540        public WorkspaceManagerScheduler(string name, int amountThreads, ExecutionEngine executionEngine)
[1700]541            : base()
542        {
[1884]543            threads = new Thread[amountThreads];
544            this.executionEngine = executionEngine;
[1700]545
[1884]546            for (int i = 0; i < threads.Length;i++ )
547            {
548                threads[i] = new Thread(this.DoScheduling);
549                threads[i].SetApartmentState(ApartmentState.MTA);
550                threads[i].Name = name + "-Thread-" + i;
551
552                switch (this.executionEngine.ThreadPriority)
553                {
554                    case 0:
555                        threads[i].Priority = ThreadPriority.AboveNormal;
556                        break;
557                    case 1:
558                        threads[i].Priority = ThreadPriority.BelowNormal;
559                        break;
560                    case 2:
561                        threads[i].Priority = ThreadPriority.Highest;
562                        break;
563                    case 3:
564                        threads[i].Priority = ThreadPriority.Lowest;
565                        break;
566                    case 4:
567                        threads[i].Priority = ThreadPriority.Normal;
568                        break;
569                }
570            }
[1700]571           
572        }
573
[1884]574        public void startScheduling()
[1700]575        {
[1884]576            foreach (Thread thread in threads)
577            {
578                thread.Start();
[1977]579                lock (this)
580                {
581                    runningThreads++;
582                }
[1884]583            }
[1700]584        }
[1884]585       
586        private void DoScheduling()
587        {           
[1700]588
[1884]589            this.executionEngine.GuiLogMessage(Thread.CurrentThread.Name + " up and running", NotificationLevel.Debug);
590            Queue<ProtocolBase> waitingProtocols = this.waitingProtocols;
[1977]591           
[1700]592            // Loop forever
593            while (true)
[1929]594            {               
[1700]595                this.wakeup.WaitOne();
596
597                // Loop while there are more protocols waiting
598                while (true)
599                {
600                    // Should the scheduler stop?
601                    if (this.shutdown)
[1977]602                    {                       
[1884]603                        this.executionEngine.GuiLogMessage(Thread.CurrentThread.Name + " terminated", NotificationLevel.Debug);
[1977]604                        lock (this)
605                        {
606                            runningThreads--;
607                        }                                           
[1700]608                        return;
[1846]609                    }
[1884]610
[1836]611                    try
612                    {
[1891]613                        ProtocolBase protocol = null;
[1884]614                        lock (this)
615                        {
[1891]616                            if (waitingProtocols.Count == 0)
617                                break;
[1884]618                            protocol = waitingProtocols.Dequeue();
619                        }
[1891]620                       
[1836]621                        ProtocolStatus status = protocol.Run();
[1700]622
[1836]623                        lock (this)
[1700]624                        {
[1836]625                            switch (status)
626                            {
627                                case ProtocolStatus.Created:
628                                    System.Diagnostics.Debug.Assert(false);
629                                    break;
630                                case ProtocolStatus.Ready:
[1884]631                                    waitingProtocols.Enqueue(protocol);
[1836]632                                    break;
633                                case ProtocolStatus.Waiting:
634                                    break;
635                                case ProtocolStatus.Terminated:
636                                    System.Diagnostics.Debug.Assert(!this.waitingProtocols.Contains(protocol));
637                                    this.RemoveProtocol(protocol);
638                                    break;
639                            }
[1700]640                        }
641                    }
[1884]642                    catch (Exception ex)
[1836]643                    {
[1977]644                        this.executionEngine.GuiLogMessage("Error during scheduling: " + ex.Message + " - " + ex.InnerException,NotificationLevel.Error);
[1836]645                    }
[1700]646                }
647            }
648        }
[1755]649        /// <summary>
650        /// Removes a protocol from the internal queue
651        /// </summary>
652        /// <param name="protocol"></param>
[1700]653        public override void RemoveProtocol(ProtocolBase protocol)
654        {
655            lock (this)
656            {
657                this.protocols.Remove(protocol);
658                if (this.protocols.Count == 0)
659                    this.Shutdown();
660            }
661        }
662
[1755]663        /// <summary>
664        /// Adds a protocol to the internal queue
665        /// </summary>
666        /// <param name="protocol"></param>
[1700]667        public override void AddProtocol(ProtocolBase protocol)
668        {
669            lock (this)
670            {
671                this.protocols.Add(protocol);
672            }
673        }
674
[1755]675        /// <summary>
676        /// Wakeup this scheduler
677        /// </summary>
678        /// <param name="protocol"></param>
[1700]679        public override void Wakeup(ProtocolBase protocol)
680        {
681            lock (this)
682            {
683                if (!this.waitingProtocols.Contains(protocol))
684                    this.waitingProtocols.Enqueue(protocol);
685                this.wakeup.Set();
686            }
687        }
688
[1755]689        /// <summary>
690        /// Terminates the scheduler
691        /// </summary>
[1700]692        public override void Shutdown()
693        {
694            this.shutdown = true;
695            this.wakeup.Set();
[1977]696
697            this.executionEngine.GuiLogMessage("Waiting for all scheduler threads to stop", NotificationLevel.Debug);
698            while (runningThreads > 0)
699            {
700                Thread.Sleep(50);
701                this.wakeup.Set();
702            }
703            this.executionEngine.GuiLogMessage("All scheduler threads stopped", NotificationLevel.Debug);
704
705            this.waitingProtocols.Clear();
706            this.protocols.Clear();           
707        }
[1700]708    }
[1449]709}
Note: See TracBrowser for help on using the repository browser.