Can a thread created in IIS notify about its timeout? - c#

We have a long running process in web application. The process runs on a seperate thread created using this:
var arguments = new object[] { startDate, endDate, m_token };
ThreadPool.QueueUserWorkItem((WaitCallback)xyzmethod, arguments);
The thread is getting terminated due to limitation of IIS on how long an unattended thread can run. It gets terminated due to session timeout or application recycle.
I want to know if a thread can notify that it is about to timeout. Or send a notification just before getting terminated?

I have an helper class created that works at least for the WebDevServer, I assume it works for IIS as well. What this does is it Register a helper with the hostingenvironment which ends up calling Stop when the host is nicely taken down. Remember that in case of an uncontrolled process exit no threads will run anymore so this method is also not being called.
Usage
protected void Button1_Click(object sender, EventArgs e)
{
var hlp = Myhelper.Create();
var arguments = new object[] { "foo", 42 };
ThreadPool.QueueUserWorkItem(hlp.FooBar, arguments);
}
Helper
public class Myhelper:IRegisteredObject
{
private Myhelper(){}
// factory
public static Myhelper Create()
{
var hlp = new Myhelper();
HostingEnvironment.RegisterObject(hlp); // register ourself!
return hlp;
}
bool keepRunning = true;
ManualResetEvent mre = new ManualResetEvent(false);
ManualResetEvent stopped = new ManualResetEvent(false);
// our DoWork method!
public void FooBar(object args)
{
EventLog.WriteEntry(".NET Runtime", "started");
// implement your long running function,
// be sure to check regularly if you need to stop processing
while (keepRunning)
{
Trace.Write("+");
mre.WaitOne(1000); // do work, (used this instead of Thread.Sleep())
}
EventLog.WriteEntry(".NET Runtime","stopped");
HostingEnvironment.UnregisterObject(this);
stopped.Set(); // we are done!
}
// this gets caled when the HostingEnvironment is stopping
public void Stop(bool immediate)
{
keepRunning = false;
mre.Set(); // signal nicely
stopped.WaitOne(200); // wait max 200 ms before returning to prevent getting stuck
}
}

Related

Forcing certain code to always run on the same thread

We have an old 3rd party system (let's call it Junksoft® 95) that we interface with via PowerShell (it exposes a COM object) and I'm in the process of wrapping it in a REST API (ASP.NET Framework 4.8 and WebAPI 2). I use the System.Management.Automation nuget package to create a PowerShell in which I instantiate Junksoft's COM API as a dynamic object that I then use:
//I'm omitting some exception handling and maintenance code for brevity
powerShell = System.Management.Automation.PowerShell.Create();
powerShell.AddScript("Add-Type -Path C:\Path\To\Junksoft\Scripting.dll");
powerShell.AddScript("New-Object Com.Junksoft.Scripting.ScriptingObject");
dynamic junksoftAPI = powerShell.Invoke()[0];
//Now we issue commands to junksoftAPI like this:
junksoftAPI.Login(user,pass);
int age = junksoftAPI.GetAgeByCustomerId(custId);
List<string> names = junksoftAPI.GetNames();
This works fine when I run all of this on the same thread (e.g. in a console application). However, for some reason this usually doesn't work when I put junksoftAPI into a System.Web.Caching.Cache and use it from different controllers in my web app. I say ususally because this actually works when ASP.NET happens to give the incoming call to the thread that junksoftAPI was created on. If it doesn't, Junksoft 95 gives me an error.
Is there any way for me to make sure that all interactions with junksoftAPI happen on the same thread?
Note that I don't want to turn the whole web application into a single-threaded application! The logic in the controllers and elswhere should happen like normal on different threads. It should only be the Junksoft interactions that happen on the Junksoft-specific thread, something like this:
[HttpGet]
public IHttpActionResult GetAge(...)
{
//finding customer ID in database...
...
int custAge = await Task.Run(() => {
//this should happen on the Junksoft-specific thread and not the next available thread
var cache = new System.Web.Caching.Cache();
var junksoftAPI = cache.Get(...); //This has previously been added to cache on the Junksoft-specific thread
return junksoftAPI.GetAgeByCustomerId(custId);
});
//prepare a response using custAge...
}
You can create your own singleton worker thread to achieve this. Here is the code which you can plug it into your web application.
public class JunkSoftRunner
{
private static JunkSoftRunner _instance;
//singleton pattern to restrict all the actions to be executed on a single thread only.
public static JunkSoftRunner Instance => _instance ?? (_instance = new JunkSoftRunner());
private readonly SemaphoreSlim _semaphore;
private readonly AutoResetEvent _newTaskRunSignal;
private TaskCompletionSource<object> _taskCompletionSource;
private Func<object> _func;
private JunkSoftRunner()
{
_semaphore = new SemaphoreSlim(1, 1);
_newTaskRunSignal = new AutoResetEvent(false);
var contextThread = new Thread(ThreadLooper)
{
Priority = ThreadPriority.Highest
};
contextThread.Start();
}
private void ThreadLooper()
{
while (true)
{
//wait till the next task signal is received.
_newTaskRunSignal.WaitOne();
//next task execution signal is received.
try
{
//try execute the task and get the result
var result = _func.Invoke();
//task executed successfully, set the result
_taskCompletionSource.SetResult(result);
}
catch (Exception ex)
{
//task execution threw an exception, set the exception and continue with the looper
_taskCompletionSource.SetException(ex);
}
}
}
public async Task<TResult> Run<TResult>(Func<TResult> func, CancellationToken cancellationToken = default(CancellationToken))
{
//allows only one thread to run at a time.
await _semaphore.WaitAsync(cancellationToken);
//thread has acquired the semaphore and entered
try
{
//create new task completion source to wait for func to get executed on the context thread
_taskCompletionSource = new TaskCompletionSource<object>();
//set the function to be executed by the context thread
_func = () => func();
//signal the waiting context thread that it is time to execute the task
_newTaskRunSignal.Set();
//wait and return the result till the task execution is finished on the context/looper thread.
return (TResult)await _taskCompletionSource.Task;
}
finally
{
//release the semaphore to allow other threads to acquire it.
_semaphore.Release();
}
}
}
Console Main Method for testing:
public class Program
{
//testing the junk soft runner
public static void Main()
{
//get the singleton instance
var softRunner = JunkSoftRunner.Instance;
//simulate web request on different threads
for (var i = 0; i < 10; i++)
{
var taskIndex = i;
//launch a web request on a new thread.
Task.Run(async () =>
{
Console.WriteLine($"Task{taskIndex} (ThreadID:'{Thread.CurrentThread.ManagedThreadId})' Launched");
return await softRunner.Run(() =>
{
Console.WriteLine($"->Task{taskIndex} Completed On '{Thread.CurrentThread.ManagedThreadId}' thread.");
return taskIndex;
});
});
}
}
}
Output:
Notice that, though the function was launched from the different threads, some portion of code got always executed always on the same context thread with ID: '5'.
But beware that, though all the web requests are executed on independent threads, they will eventually wait for some tasks to get executed on the singleton worker thread. This will eventually create a bottle neck in your web application. This is anyway your design limitation.
Here is how you could issue commands to the Junksoft API from a dedicated STA thread, using a BlockingCollection class:
public class JunksoftSTA : IDisposable
{
private readonly BlockingCollection<Action<Lazy<dynamic>>> _pump;
private readonly Thread _thread;
public JunksoftSTA()
{
_pump = new BlockingCollection<Action<Lazy<dynamic>>>();
_thread = new Thread(() =>
{
var lazyApi = new Lazy<dynamic>(() =>
{
var powerShell = System.Management.Automation.PowerShell.Create();
powerShell.AddScript("Add-Type -Path C:\Path\To\Junksoft.dll");
powerShell.AddScript("New-Object Com.Junksoft.ScriptingObject");
dynamic junksoftAPI = powerShell.Invoke()[0];
return junksoftAPI;
});
foreach (var action in _pump.GetConsumingEnumerable())
{
action(lazyApi);
}
});
_thread.SetApartmentState(ApartmentState.STA);
_thread.IsBackground = true;
_thread.Start();
}
public Task<T> CallAsync<T>(Func<dynamic, T> function)
{
var tcs = new TaskCompletionSource<T>(
TaskCreationOptions.RunContinuationsAsynchronously);
_pump.Add(lazyApi =>
{
try
{
var result = function(lazyApi.Value);
tcs.SetResult(result);
}
catch (Exception ex)
{
tcs.SetException(ex);
}
});
return tcs.Task;
}
public Task CallAsync(Action<dynamic> action)
{
return CallAsync<object>(api => { action(api); return null; });
}
public void Dispose() => _pump.CompleteAdding();
public void Join() => _thread.Join();
}
The purpose of using the Lazy class is for surfacing a possible exception during the construction of the dynamic object, by propagating it to the callers.
...exceptions are cached. That is, if the factory method throws an exception the first time a thread tries to access the Value property of the Lazy<T> object, the same exception is thrown on every subsequent attempt.
Usage example:
// A static field stored somewhere
public static readonly JunksoftSTA JunksoftStatic = new JunksoftSTA();
await JunksoftStatic.CallAsync(api => { api.Login("x", "y"); });
int age = await JunksoftStatic.CallAsync(api => api.GetAgeByCustomerId(custId));
In case you find that a single STA thread is not enough to serve all the requests in a timely manner, you could add more STA threads, all of them running the same code (private readonly Thread[] _threads; etc). The BlockingCollection class is thread-safe and can be consumed concurrently by any number of threads.
If you did not say that was a 3rd party tool, I would have asumed it is a GUI class. For practical reasons, it is a very bad idea to have multiple threads write to them. .NET enforces a strict "only the creating thread shall write" rule, from 2.0 onward.
WebServers in general and ASP.Net in particular use a pretty big thread pool. We are talking 10's to 100's of Threads per Core. That means it is really hard to nail any request down to a specific Thread. You might as well not try.
Again, looking at the GUI classes might be your best bet. You could basically make a single thread with the sole purpose of immitating a GUI's Event Queue. The Main/UI Thread of your average Windows Forms application, is responsible for creating every GUI class instance. It is kept alive by polling/processing the event queue. It ends onlyx when it receies a cancel command, via teh Event Queue. Dispatching just puts orders into that Queue, so we can avoid Cross-Threading issues.

How to properly delay when there is no task to wait for

I have a task that is waiting for a property to be set to true (= completed). The way I am receiving that property value change is via EventHandler (System.Diagnostics.Process.OutputDataReceived to be exact - it continuously reads the output of another process until the correct output is provided). However checking for the property all the time feels somewhat inefficiencient. I have tried adding a small delay of one tick because I believe I can allow myself such a wait if that would save CPU time, but I read .NET struggles with fractional milliseconds. Can I improve this code?
private ConcurrentBag<string> _allMessages = new ConcurrentBag<string>();
public OutputRetriever()
{
var process = new System.Diagnostics.Process();
...
process.OutputDataReceived += OutputDataReceived;
process.Start();
}
public async Task<string[]> GetAllOutput()
{
while (!IsCompleted)
{
// how to properly wait here?
// await Task.Delay(TimeSpan.FromTicks(1)); // is this ok?
}
return _allMessages.ToArray();
}
private void ConsoleDataReceived(object sender, DataReceivedEventArgs e)
{
_allMessages.Add(e?.Data);
if (e?.Data == "success")
{
IsCompleted = true;
}
}
The timers in Windows have a resolution of approx. 16 ms, so any delay below 16 ms cannot be precisely achieved. This applies to any timer - the .NET timers are just wrappers for Windows native timers.
Instead of busy-waiting in a loop, create a custom TaskCompletionSource<T> and return a Task that can be awaited.
class OutputRetriever
{
private readonly ConcurrentBag<string> _allMessages = new ConcurrentBag<string>();
private readonly TaskCompletionSource<string[]> _taskSource
= new TaskCompletionSource<string[]>();
// Note: this method is not async anymore
public Task<string[]> GetAllOutput()
{
// We just return a task that can be awaited
return _taskSource.Task;
}
void ConsoleDataReceived(object sender, DataReceivedEventArgs e)
{
_allMessages.Add(e?.Data);
if (e?.Data == "success")
{
// Here we notify that the task is completed by setting the result
_taskSource.SetResult(_allMessages.ToArray());
}
}
}
Now the clients can simply await the results as usual:
var receiver = new OutputReceiver();
string[] messages = await receiver.GetAllOutput();

Changing thread context in C# console application

I have a C# console app in which I can get, among other things, input via a TCP socket connection. How do I switch to the main thread when I receive an input via the receive function over the socket?
So similar to something like this in WPF:
public void TaskDispatcher()
{
if (DispatcherObjectForTaskDispatcher.Thread != System.Threading.Thread.CurrentThread)
DispatcherObjectForTaskDispatcher.Invoke(new TaskDispatcherDelegate(TaskDispatcher));
else
{
// Do some thing in the UI thread
}
}
Just use a Producer-Consumer pattern as in the working example below. Enqueue jobs from other threads and let the main thread process the queued jobs from a job queue.
I used a timer thread and a user input thread to simulate 2 threads producing jobs. You could implement your TCP events to just enqueue a job in the job queue. You should store any relevant objects as arguments inside your job, for later processing. You must also define a function to be called by the job, which will run in the main thread.
The main thread is used here just for dequeueing jobs and processing them, but you could use any other thread for this purpose if you improve this code a little bit.
You could even implement multi-threading processing, on which more processing threads dequeue from the same job queue. Be aware this brings new concurrency problems which you may have to deal with. That's the drawback for gaining much more processing power in your application. Some scenarios are suitable for multi-threading processing (e.g. video / image processing) while some others are not.
The code below is a full working example written in a Visual Studio 2017, DotNET 4.6.1, console application project. Just copy, paste, and hit F5.
using System;
using System.Collections.Concurrent;
using System.Diagnostics;
using System.Threading;
// Compiled and tested in: Visual Studio 2017, DotNET 4.6.1
namespace MyNamespace
{
public class Program
{
public static void Main(string[] args)
{
MyApplication app = new MyApplication();
app.Run();
}
}
public class MyApplication
{
private BlockingCollection<Job> JobQueue = new BlockingCollection<Job>();
private CancellationTokenSource JobCancellationTokenSource = new CancellationTokenSource();
private CancellationToken JobCancellationToken;
private Timer Timer;
private Thread UserInputThread;
public void Run()
{
// Give a name to the main thread:
Thread.CurrentThread.Name = "Main";
// Fires a Timer thread:
Timer = new Timer(new TimerCallback(TimerCallback), null, 1000, 2000);
// Fires a thread to read user inputs:
UserInputThread = new Thread(new ThreadStart(ReadUserInputs))
{
Name = "UserInputs",
IsBackground = true
};
UserInputThread.Start();
// Prepares a token to cancel the job queue:
JobCancellationToken = JobCancellationTokenSource.Token;
// Start processing jobs:
ProcessJobs();
// Clean up:
JobQueue.Dispose();
Timer.Dispose();
UserInputThread.Abort();
Console.WriteLine("Done.");
}
private void ProcessJobs()
{
try
{
// Checks if the blocking collection is still up for dequeueing:
while (!JobQueue.IsCompleted)
{
// The following line blocks the thread until a job is available or throws an exception in case the token is cancelled:
JobQueue.Take(JobCancellationToken).Run();
}
}
catch { }
}
private void ReadUserInputs()
{
// User input thread is running here.
ConsoleKey key = ConsoleKey.Enter;
// Reads user inputs and queue them for processing until the escape key is pressed:
while ((key = Console.ReadKey(true).Key) != ConsoleKey.Escape)
{
Job userInputJob = new Job("UserInput", this, new Action<ConsoleKey>(ProcessUserInputs), key);
JobQueue.Add(userInputJob);
}
// Stops processing the JobQueue:
JobCancellationTokenSource.Cancel();
}
private void ProcessUserInputs(ConsoleKey key)
{
// Main thread is running here.
Console.WriteLine($"You just typed '{key}'. (Thread: {Thread.CurrentThread.Name})");
}
private void TimerCallback(object param)
{
// Timer thread is running here.
Job job = new Job("TimerJob", this, new Action<string>(ProcessTimer), "A job from timer callback was processed.");
JobQueue.TryAdd(job); // Just enqueues the job for later processing
}
private void ProcessTimer(string message)
{
// Main thread is running here.
Console.WriteLine($"{message} (Thread: {Thread.CurrentThread.Name})");
}
}
/// <summary>
/// The Job class wraps an object's method call, with or without arguments. This method is called later, during the Job execution.
/// </summary>
public class Job
{
public string Name { get; }
private object TargetObject;
private Delegate TargetMethod;
private object[] Arguments;
public Job(string name, object obj, Delegate method, params object[] args)
{
Name = name;
TargetObject = obj;
TargetMethod = method;
Arguments = args;
}
public void Run()
{
try
{
TargetMethod.Method.Invoke(TargetObject, Arguments);
}
catch(Exception ex)
{
Debug.WriteLine($"Unexpected error running job '{Name}': {ex}");
}
}
}
}

Replacing Thread.Suspend and Thread.Resume in a windows service

We have a service that does the following basic workflow:
1) Starts, reads config settings and performs some calculations in a large loop.
2) Each iteration of the loop, it needs to be able to check if the service has been told to stop. It performs database fetches, calculations then stores results. I am not confident on how well the code is done wrt SQL transactions so at this stage, happy to assume we are only checking for service stop at the start of each iteration.
3) After performing all iterations, the service "sleeps" for a period of time. Could be 5 minutes. Could be 12 hours. It needs to be able to "stop" in this sleep period!
Currently this is performed by the following:
private int threadSleepMinutes = 60;
private readonly Mutex mutTerminateService = new Mutex(false);
private Thread serviceThread;
private Thread serviceStopThread;
// Use this flag to allow the Start op to wait for serviceStopThread
// to get going before continuing to create the main loop thread
private volatile bool stopService = true;
public void Start()
{
this.serviceStopThread = new Thread(this.RunServiceStopThread);
this.serviceStopThread.IsBackground = true;
this.serviceStopThread.Start();
while (stopService)
{
Thread.Sleep(100);
}
// Some things renamed to anonymise... you get the idea!
this.serviceThread = new Thread(this.BigLoopMethod);
this.serviceThread.IsBackground = true;
this.serviceThread.Start();
}
public void Stop()
{
// Release the mutex to terminate the service
serviceStopThread.Resume();
// Wait 5s max
int timeout = 5000;
while (this.serviceThread.IsAlive && timeout > 0)
{
Thread.Sleep(100);
timeout -= 100;
}
}
private void RunServiceStopThread()
{
// To guarantee the same thread takes the mutex
// and releases it in dot net 4, do both ops in this single thread!
// Dot net 4 the Start() and Stop() are now usually on different threads.
mutTerminateService.WaitOne();
stopService = false;
// Suspend ourself
serviceStopThread.Suspend();
// Release the mutex
mutTerminateService.ReleaseMutex();
}
public void BigLoopMethod()
{
try
{
do
{
bool moreOperationsToGo = true; // Just dummy flags and 'stuff' methods here
while (moreOperationsToGo && !mutTerminateService.WaitOne(0))
{
DoStuff();
}
// Using this mutex here to sleep nicely - event driven.
// Gracefully continues after timeout and gracefully exits if
// triggered by the mutex.
}
while (!mutTerminateService.WaitOne(this.threadSleepMinutes * 60000));
}
catch (Exception ex)
{
// Exception handling & logging here
}
}
Now I get messages saying Suspend and Resume are deprecated. In my situation, I know exactly what code the suspend was run on since the call itself is what suspended it! Resume, I know exactly what it is going to do. The only reason this was even done in the first place was because the mutex worked fine in Start() and Stop() in dot net 3.5 but dot net 4.0 changed so that Start() and Stop() were in different threads AND they marked the workaround as obsolete!
Is there a nice way, non-obsolete way of doing this?
Thanks
Unless you are using mutex for inter-process communication, i.e. cancelling your worker thread from another process - I believe there is an easier way to implement a worker thread with cancellation in .net 4.0. You can use a cancellation token, and wait with timeout on it - it will signal if token was cancelled. Complete solution (partially using your code) below:
using System;
using System.Threading;
class App
{
static void Main()
{
var t = new Test();
t.Start();
Thread.Sleep(10000);
Console.WriteLine("aborting");
t.Stop();
}
}
class Test
{
private int threadSleepMinutes = 60;
private Thread serviceThread;
private CancellationTokenSource tokenSource;
public void Start()
{
// Some things renamed to anonymise... you get the idea!
this.tokenSource = new CancellationTokenSource();
this.serviceThread = new Thread(this.BigLoopMethod);
this.serviceThread.IsBackground = true;
this.serviceThread.Start();
}
public void Stop()
{
tokenSource.Cancel();
// Wait 5s max
int timeout = 5000;
if (!serviceThread.Join(timeout))
{
serviceThread.Abort();
}
}
public void BigLoopMethod()
{
try
{
var token = tokenSource.Token;
do
{
int operationsToGo = 4; // Just dummy flags and 'stuff' methods here
while (operationsToGo > 0 && !token.IsCancellationRequested)
{
Console.WriteLine("work");
Thread.Sleep(1000);//DoStuff();
operationsToGo--;
}
Console.WriteLine("no more work");
}
while (!token.WaitHandle.WaitOne(this.threadSleepMinutes * 60000));
}
catch (Exception ex)
{
// Exception handling & logging here
}
}
}
You don't need a "stop" thread. The fact that the start method triggers the BigLoopMethod will be sufficient. All you need in stop is to signal the mutex and then join the thread (Thread.Join() will wait for the thread to halt) with an appropriate timeout. I would recommend for robustness to thread abort if your thread doesn't join within an appropriate time to forcibly kill the service.
So in psuedo code:
void Start()
{
OpenMutex();
TakeMutex();
KickOffMyThread();
}
void Stop();
{
SignalMutex();
if (!MyThread.Join(Timeout))
{
MyThread.Abort();
Environment.Exit(1); // Die as thread won't join
}
}
void MyThread()
{
while (!TakeMutex(sleeptime)
{
DoLongWork();
}
//Thread was signalled, exiting.
}

c# execute 2 threads simultaneously

I am trying to reproduce a threading error condition within an HTTP Handler.
Basically, the ASP.net worker procecss is creating 2 threads which invoke the HTTP handler in my application simultaneously when a certain page loads.
Inside the http handler, is a resource which is not thread safe. Hence, when the 2 threads try to access it simultaneously an exception occurs.
I could potentially, put a lock statement around the resource, however I want to make sure that it is infact the case. So I wanted to create the situation in a console application first.
But i cant get 2 threads to execute a method at the same time like asp.net wp does. So, my question is how can you can create 2 threads which can execute a method at the same time.
Edit:
The underlying resource is a sql database with a user table (has a name column only). Here is a sample code i tried.
[TestClass]
public class UnitTest1
{
[TestMethod]
public void Linq2SqlThreadSafetyTest()
{
var threadOne = new Thread(new ParameterizedThreadStart(InsertData));
var threadTwo = new Thread(new ParameterizedThreadStart(InsertData));
threadOne.Start(1); // Was trying to sync them via this parameter.
threadTwo.Start(0);
threadOne.Join();
threadTwo.Join();
}
private static void InsertData( object milliseconds )
{
// Linq 2 sql data context
var database = new DataClassesDataContext();
// Database entity
var newUser = new User {Name = "Test"};
database.Users.InsertOnSubmit(newUser);
Thread.Sleep( (int) milliseconds);
try
{
database.SubmitChanges(); // This statement throws exception in the HTTP Handler.
}
catch (Exception exception)
{
Debug.WriteLine(exception.Message);
}
}
}
You could just set a static time to start your work like this.
private static DateTime startTime = DateTime.Now.AddSeconds(5); //arbitrary start time
static void Main(string[] args)
{
ThreadStart threadStart1 = new ThreadStart(DoSomething);
ThreadStart threadStart2 = new ThreadStart(DoSomething);
Thread th1 = new Thread(threadStart1);
Thread th2 = new Thread(threadStart2);
th1.Start();
th2.Start();
th1.Join();
th2.Join();
Console.ReadLine();
}
private static void DoSomething()
{
while (DateTime.Now < startTime)
{
//do nothing
}
//both threads will execute code here concurrently
}

Categories