/// <summary> /// Execute a code block with a maximum limit on time and memory. /// </summary> /// <param name="timeSpan">Timeout in timespan</param> /// <param name="withinCustomLimits">Function used to determine if the codeBlock is within custom limits, such as with algorithm manager /// timing individual time loops, return a non-null and non-empty string with a message indicating the error/reason for stoppage</param> /// <param name="codeBlock">Action codeblock to execute</param> /// <param name="memoryCap">Maximum memory allocation, default 1024Mb</param> /// <param name="sleepIntervalMillis">Sleep interval between each check in ms</param> /// <param name="workerThread">The worker thread instance that will execute the provided action, if null /// will use a <see cref="Task"/></param> /// <returns>True if algorithm exited successfully, false if cancelled because it exceeded limits.</returns> public bool ExecuteWithTimeLimit(TimeSpan timeSpan, Func <IsolatorLimitResult> withinCustomLimits, Action codeBlock, long memoryCap = 1024, int sleepIntervalMillis = 1000, WorkerThread workerThread = null) { workerThread?.Add(codeBlock); var task = workerThread == null //Launch task ? Task.Factory.StartNew(codeBlock, CancellationTokenSource.Token) // wrapper task so we can reuse MonitorTask : Task.Factory.StartNew(() => workerThread.FinishedWorkItem.WaitOne(), CancellationTokenSource.Token); try { return(MonitorTask(task, timeSpan, withinCustomLimits, memoryCap, sleepIntervalMillis)); } catch (Exception) { if (!task.IsCompleted) { // lets free the wrapper task even if the worker thread didn't finish workerThread?.FinishedWorkItem.Set(); } throw; } }