Example #1
0
        public static bool MakeThread(IODThread threadClass, bool isAutoStart = false, string groupName = "")
        {
            if (threadClass.IsInit)
            {
                return(false);
            }
            ODThread thread = new ODThread(threadClass.GetThreadRunIntervalMS(), threadClass.OnThreadRun);

            thread.Name = threadClass.GetThreadName();
            if (groupName != "")
            {
                thread.GroupName = groupName;
            }
            thread.AddExceptionHandler(new ExceptionDelegate(threadClass.OnThreadException));
            thread.AddExitHandler(new WorkerDelegate(threadClass.OnThreadExit));
            if (isAutoStart)
            {
                thread.Start();
            }
            threadClass.IsInit   = true;
            threadClass.ODThread = thread;
            return(true);
        }
Example #2
0
		///<summary>Worker method for _odThreadEServices.  Call StartEServiceMonitoring() to start monitoring eService signals instead of calling this method directly.</summary>
		private void ProcessEServiceSignals(ODThread odThread) {
			//--------------------------------------------------------------------------------------------------------------------------------------------
			//This method can get enhanced later to be more generic like ProcessSignals where it grabs a list of eService signals and loops through them.
			//For now, we only care about the status of the Listener Service and I want the first edition of this method to be as light as possible.
			//--------------------------------------------------------------------------------------------------------------------------------------------
			Color colorCur=_colorEServicesBackground;
			//The listener service will have a local heartbeat every 5 minutes so it's overkill to check every time timerSignals_Tick fires.
			//Only check the Listener Service status once a minute.
			//The downside to doing this is that the menu item will stay red up to one minute when a user wants to stop monitoring the service.
			eServiceSignalSeverity listenerStatus=EServiceSignals.GetServiceStatus(eServiceCode.ListenerService);
			if(listenerStatus==eServiceSignalSeverity.None) {
				//This office has never had a valid listener service running and does not have more than 5 patients set up to use the listener service.
				//Quit the thread so that this computer does not waste its time sending queries to the server every minute.
				odThread.QuitAsync();
				return;
			}
			if(listenerStatus==eServiceSignalSeverity.Critical) {
				_colorEServicesBackground=COLOR_ESERVICE_ALERT_BACKGROUND;
			}
			else {
				_colorEServicesBackground=SystemColors.Control;
			}
			if(colorCur!=_colorEServicesBackground) {
				//Since the status changed, redraw the eServices menu item.
				BeginInvoke(new InvalidateEServicesMenuItemDelegate(InvalidateEServicesMenuItem));
			}
		}
Example #3
0
		///<summary>Stops the eService monitoring thread and sets the eServices menu item colors to a disabled state because the Log On window will be shown next.</summary>
		private void StopEServiceMonitoring() {
			if(_odThreadEServices==null) {
				return;//Nothing to do, the service was already stopped.
			}
			//QuitSync the thread just because it has the power to live for up to a minute which is unnecessary.
			//There is no reason to wait more than 1 second for the thread to quit.
			_odThreadEServices.QuitSync(1000);
			_odThreadEServices=null;
			//Set the background color of the menu item back to gray just in case it was red for the last user that was logged in.
			_colorEServicesBackground=SystemColors.Control;
			InvalidateEServicesMenuItem();//No need to invoke this method, we should always be in the main thread when stopping the thread.
		}
Example #4
0
		///<summary>Starts the eService monitoring thread that will run once a minute.  Only runs if the user currently logged in has the eServices permission.</summary>
		private void StartEServiceMonitoring() {
			//If the user currently logged in has permission to view eService settings, turn on the listener monitor.
			if(Security.CurUser==null || !Security.IsAuthorized(Permissions.EServicesSetup,true)) {
				return;//Do not start the listener service monitor for users without permission.
			}
			if(_odThreadEServices==null) {
				//Create a separate thread that will run every 60 seconds to monitor eService signals.
				_odThreadEServices=new ODThread(60000,ProcessEServiceSignals);
				//Add exception handling just in case MySQL is unreachable at any point in the lifetime of this session.
				_odThreadEServices.AddExceptionHandler(EServiceMonitoringException);
				_odThreadEServices.Name="eService Monitoring Thread";
				_odThreadEServices.GroupName="eServiceThreads";
			}
			_odThreadEServices.Start();
		}
Example #5
0
 ///<summary>What the thread does right before it dies.</summary>
 public virtual void OnThreadExit(ODThread odThread)
 {
 }
Example #6
0
 ///<summary>What the thread does every time the specified interval of time has passed.</summary>
 public abstract void OnThreadRun(ODThread odThread);
Example #7
0
		///<summary>Spread the given actions over the given numThreads. Blocks until threads have completed or timeout is reached.
		///If numThreads is not provided then numThreads will default to Environment.ProcessorCount. This is typically what you should let happen.
		///If onException is provided then one and only one onException event will be raised when any number of exceptions occur.
		///All actions will run to completion regardless if any/all throw unhandled exceptions.
		///If the timeout is reached, all threads will be killed and their corresponding actions will not complete.  This can leave data in an 
		///undefined state, for example, if an action times out before instantiating an object, the object will be null.
		///Throws exception on main thread if any action throws and unhandled exception and no onException was provided.</summary>
		public static void RunParallel(List<Action> listActions,int timeoutMS=Timeout.Infinite,int numThreads=0,ExceptionDelegate onException=null,
			bool doRunOnCurrentThreadIf1Processor=false) 
		{
			//Use as many threads as required by default.
			int threadCount=numThreads;
			if(threadCount<=0) {
				//No requirement on thread count was given so use the number of processor cores.
				threadCount=Environment.ProcessorCount;
				//Using at least 8 has neglibile negative impact so if the user didn't otherwise specify, use at least 8 threads.
				if(threadCount<8) {
					threadCount=8;
				}
			}
			Exception exceptionFirst=null;
			void HandleException() {
				if(exceptionFirst!=null) { //One of the actions threw an unhandled exception.
					if(onException==null) { //No handler was provided so throw. 
						ExceptionDispatchInfo exInfo=ExceptionDispatchInfo.Capture(exceptionFirst);
						exInfo.Throw();
					}
					//Caller wants to know about this exception so tell them.
					onException(exceptionFirst);
				}
			}
			if(threadCount==1 && doRunOnCurrentThreadIf1Processor) {
				foreach(Action action in listActions) {
					try {
						action();
					}
					catch(Exception ex) {
						exceptionFirst=exceptionFirst??ex;//First exception in will get thrown.
					}
				}
				HandleException();
				return;
			}
			//Make a group of threads to spread out the workload.
			List<Action> listActionsCur=new List<Action>();
			int actionsPerThread=(int)Math.Ceiling((double)listActions.Count/threadCount);
			object locker=new object();
			//No one outside of this method cares about this group name. They have no authority over this group.
			int threadID=1;
			string threadGroupGUID=Guid.NewGuid().ToString();
			string threadGroupName="ODThread.ThreadPool()"+threadGroupGUID;
			for(int i = 0;i<listActions.Count;i++) {
				//Add to the current thread pool.
				listActionsCur.Add(listActions[i]);
				//If this thread pool is full then start it.
				if(listActionsCur.Count==actionsPerThread||i==(listActions.Count-1)) {
					ODThread odThread=new ODThread(new WorkerDelegate((ODThread o) => {
						((List<Action>)o.Tag).ForEach(x => x());
					}));
					odThread.Tag=new List<Action>(listActionsCur);
					odThread.Name=threadGroupName+"-"+threadID;
					odThread.GroupName=threadGroupName;
					odThread.AddExceptionHandler(new ExceptionDelegate((Exception e) => {
						lock (locker) {
							if(exceptionFirst==null) { //First in wins.
								exceptionFirst=e;
							}
						}
					}));
					//We just started a new thread pool so start a new one.
					listActionsCur.Clear();
					odThread.Start(true);
					threadID++;
				}
			}
			//Wait for all appointment drawing threads to finish.
			JoinThreadsByGroupName(timeoutMS,threadGroupName,true);
			//We are back on the thread that called us now.
			HandleException();
		}
Example #8
0
        ///<summary>Spread the given actions over the given numThreads. Blocks until threads have completed or timeout is reached.
        ///If numThreads is not provided then numThreads will default to Environment.ProcessorCount. This is typically what you should let happen.
        ///If onException is provided then one and only one onException event will be raised when any number of exceptions occur.
        ///All actions will run to completion regardless if any/all throw unhandled exceptions.
        ///Throws exception on main thread if any action throws and unhandled exception and no onException was provided.</summary>
        public static void RunParallel(List <Action> listActions, TimeSpan timeout, int numThreads = 0, ExceptionDelegate onException = null)
        {
            //Use as many threads as required by default.
            int threadCount = numThreads;

            if (threadCount <= 0)
            {
                //No requirement on thread count was given so use the number of processor cores.
                threadCount = Environment.ProcessorCount;
                //Using at least 8 has neglibile negative impact so if the user didn't otherwise specify, use at least 8 threads.
                if (threadCount < 8)
                {
                    threadCount = 8;
                }
            }
            //Make a group of threads to spread out the workload.
            List <Action> listActionsCur   = new List <Action>();
            Exception     exceptionFirst   = null;
            int           actionsPerThread = (int)Math.Ceiling((double)listActions.Count / threadCount);
            object        locker           = new object();
            //No one outside of this method cares about this group name. They have no authority over this group.
            string threadGroupName = "ODThread.ThreadPool()" + Guid.NewGuid().ToString();

            for (int i = 0; i < listActions.Count; i++)
            {
                //Add to the current thread pool.
                listActionsCur.Add(listActions[i]);
                //If this thread pool is full then start it.
                if (listActionsCur.Count == actionsPerThread || i == (listActions.Count - 1))
                {
                    ODThread odThread = new ODThread(new WorkerDelegate((ODThread o) => {
                        ((List <Action>)o.Tag).ForEach(x => x());
                    }));
                    odThread.Tag       = new List <Action>(listActionsCur);
                    odThread.GroupName = threadGroupName;
                    odThread.AddExceptionHandler(new ExceptionDelegate((Exception e) => {
                        lock (locker) {
                            if (exceptionFirst == null)                            //First in wins.
                            {
                                exceptionFirst = e;
                            }
                        }
                    }));
                    //We just started a new thread pool so start a new one.
                    listActionsCur.Clear();
                    odThread.Start(true);
                }
            }
            //Wait for all appointment drawing threads to finish.
            JoinThreadsByGroupName((int)timeout.TotalMilliseconds, threadGroupName, true);
            //We are back on the thread that called us now.
            if (exceptionFirst != null)            //One of the actions threw an unhandled exception.
            {
                if (onException == null)           //No handler was provided so throw.
                {
                    throw exceptionFirst;
                }
                //Caller wants to know about this exception so tell them.
                onException(exceptionFirst);
            }
        }