private void FormProgressStatus_Shown(object sender, EventArgs e)
        {
            //Spawn a separate thread that will monitor if this progress form should has indicated that it needs to close.
            //This thread will be a fail-safe in the sense that it will constantly monitor a separate indicator that this window should close.
            ODThread threadForceCloseMonitor = new ODThread(100, new ODThread.WorkerDelegate((o) => {
                if (_hasClosed)
                {
                    o.QuitAsync();                    //Stop monitoring as soon as we detect that this window has been "closed".
                    return;
                }
                if (ForceClose)
                {
                    //Something triggered the fact that this form should have closed.
                    this.InvokeIfRequired(() => {
                        DialogResult = DialogResult.OK;
                        ODException.SwallowAnyException(() => Close()); //Can throw exceptions for many reasons.
                    });
                    o.QuitAsync();                                      //We tried our best to "unstuck" this window.  The user will have to Alt + F4 this window closed?
                    return;
                }
            }));

            threadForceCloseMonitor.AddExceptionHandler((ex) => {
                ex.DoNothing();                //The form might stay open forever which was already happening... we tried our best.
            });
            threadForceCloseMonitor.Name = "FormProgressStatusMonitor_" + DateTime.Now.Ticks;
            threadForceCloseMonitor.Start();
        }
        ///<summary>Non-blocking call. Every type of progress window should eventually call this method which does the hard stuff for the calling method.
        ///Spawns a separate thread that will instantiate a FormProgressBase within the new thread's context by invoking the func passed in.
        ///The FormProgressBase that funcGetNewProgress returns should be a form that is instatiated within the func (in order to avoid cross-threading).
        ///The global static FormProgressCurS will get set to the newly instantiated progress so that the entire application knows progress is showing.
        ///Finally returning a close action for the calling method to invoke whenever long computations are finished.
        ///Two critical portions of the closing method are 1 - it closes progress gracefully and 2 - FormProgressCurS gets set to null.</summary>
        public static Action ShowProgressBase(Func <FormProgressBase> funcGetNewProgress, string threadName = "Thread_ODProgress_ShowProgressBase")
        {
            if (ODEnvironment.IsWindows7(false) || ODInitialize.IsRunningInUnitTest)
            {
                return(new Action(() => {
                    //Do nothing.
                }));
            }
            FormProgressBase FormPB      = null;
            ManualResetEvent manualReset = new ManualResetEvent(false);
            ODThread         odThread    = new ODThread(o => {
                //It is very important that this particular thread instantiates the form and not the calling method.
                //This is what allows the progress window to show and be interacted with without joining or invoking back to the parent thread.
                FormPB = funcGetNewProgress();
                AddActiveProgressWindow(FormPB);                //Let the entire application know that a progress window is showing.
                FormPB.Shown      += (obj, eArg) => manualReset.Set();
                FormPB.FormClosed += (obj, eArg) => RemoveActiveProgressWindow(FormPB);
                FormPB.ShowDialog();                //We cannot utilize the "owner" overload because that would cause a cross threaded exception.
            });

            odThread.SetApartmentState(ApartmentState.STA);            //This is required for ReportComplex due to the history UI elements.
            odThread.AddExceptionHandler(e => e.DoNothing());          //The progress window had an exception... Not worth crashing the program over this.
            odThread.Name = threadName;
            odThread.Start();
            //Force the calling thread to wait for the progress window to actually show to the user before continuing.
            manualReset.WaitOne();
            return(() => {
                FormPB.ForceClose = true;
                odThread.Join(Timeout.Infinite);
            });
        }
Exemple #3
0
        ///<summary>Sends a requests to ODCloudClient and waits for a response. Throws any exception that ODCloudClient returns.</summary>
        private static string SendToODCloudClientSynchronously(ODCloudClientData cloudClientData, CloudClientAction cloudClientAction, int timeoutSecs = 30)
        {
            bool      hasReceivedResponse   = false;
            string    odCloudClientResponse = "";
            Exception exFromThread          = null;

            void onReceivedResponse(string response)
            {
                hasReceivedResponse   = true;
                odCloudClientResponse = response;
            }

            ODThread thread = new ODThread(o => {
                SendToODCloudClient(cloudClientData, cloudClientAction, onReceivedResponse);
            });

            thread.Name = "SendToODCloudClient";
            thread.AddExceptionHandler(e => exFromThread = e);
            thread.Start();
            DateTime start = DateTime.Now;

            ODProgress.ShowAction(() => {
                while (!hasReceivedResponse && exFromThread == null && (DateTime.Now - start).TotalSeconds < timeoutSecs)
                {
                    Thread.Sleep(100);
                }
            });
            if (exFromThread != null)
            {
                throw exFromThread;
            }
            if (!hasReceivedResponse)
            {
                throw new ODException("Unable to communicate with OD Cloud Client.", ODException.ErrorCodes.ODCloudClientTimeout);
            }
            CloudClientResult result = JsonConvert.DeserializeObject <CloudClientResult>(odCloudClientResponse);

            if (result.ResultCodeEnum == CloudClientResultCode.ODException)
            {
                ODException odEx = JsonConvert.DeserializeObject <ODException>(result.ResultData);
                throw odEx;
            }
            if (result.ResultCodeEnum == CloudClientResultCode.Error)
            {
                throw new Exception(result.ResultData);
            }
            return(result.ResultData);
        }
Exemple #4
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;
		}
Exemple #5
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();
		}
Exemple #6
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();
		}
Exemple #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.
        ///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);
            }
        }