What Is the Meaning of Thread-Agility in ASP.NET

What is the meaning of thread-agility in ASP.Net?

It means that IIS is free to use more than one thread to handle a single request, although not in parallel.

Basically, IIS tries to perform I/O operations asynchronously, thus freeing the calling thread for the duration of the operation. That thread is returned to the pool and can be used to handle other requests in the meantime.

When the asynchronous I/O operation completes, control can be returned to a thread other than the one that originally handled the request (since that thread can be busy elsewhere), so the request can continue being processed as soon as possible.

Does a .NET service exhibit thread agility?

No. A windows service is not managed by the IIS pipeline and any threads that are created must be created by the service code itself.

Pitfalls of IIS 7.5, thread agility and static variables

This isn't an issue with thread agility, it's an issue with using static variables. Static variables are static for the PROCESS, not one thread. So, a static variable in ASP.NET is shared by EVERY request being made to your site. So, ask yourself: is this static variable MEANT to be shared among every requester, or is it specific to ONE requester? For example:

static int TotalPageHits; //Count the number of times a page has been requested

Clearly, this is perfectly fine data to share for ALL users. On the other hand:

static string CurrentUserId; //DANGER WILL ROBINSON!!!!

Any variable specific to one requester you want to put in HttpContext.Current.Items.

Can code after 'await' run in different thread in ASP.NET?

For ASP.NET Classic (.NET Framework), there is a special AspNetSynchronizationContext, the continuation will post back to the original context thread.

ASP.NET Core there isn’t one. If you inspect SynchronizationContext.Current you’ll find that it’s set to null. As such, a continuation is free to use what ever thread it chooses, and will suffer no classic deadlocks in that respect


Update

Some great corrections from @StephenCleary in the comments

Minor correction : on classic ASP.NET, the SynchronizationContext
represents the request context, not a specific thread.

The method may resume on any thread pool thread after the await.
The deadlock occurs because there is a lock as part of that request
context
to ensure that only one thread at a time may be in the
request context.

So, when the async method is ready to resume, a thread pool thread
is taken which enters the request context and tries to take that
lock. If there's another thread blocked on that task in the context, the lock is already taken and a deadlock will occur

Is this code thread safe in ASP.NET MVC 4?

Your second solution would work fine. The first one is not thread safe at all. Caching a value in a static variable exposes it to all threads, and if you have two or more simultaneous requests, it's highly likely they will read some other request's value. You think it's extremely unlikely, well... it's not, quite the opposite.

Besides, if you really want a value to be shared across multiple threads, you should use some synchronization mechanism to ensure correctness. In your first example, you access _userName 3 times (2 reads and 1 write). You can get into a situation where this variable ends up different values, so you should enclose everything in a lock. And that's only when you explicitly want to share this information between threads.

The second approach works because the value of HttpContext.Current is retrieved from the current execution context (so it's dependent on the current thread).

Oh one more thing: in an ASP.NET application you shouldn't rely on thread-local storage because of thread agility, so if you need to cache values use the HttpContext instead. You have an Items property which lets you store values for the duration of the current request only. but in your particular example, you don't have to cache this value, because it's already retrieved from the HTTP context.

Is the Mutex class safe to use within an ASP.NET request?

Under thread agility, ASP.NET may use a different thread for different handler calls. It's rare. But occasionally you'll see that your module's BeginRequest handler executed on a different thread from the page's OnPreRender handler, that sort of thing.

If you're using a using clause and creating and disposing of the Mutex within the same method call, you will probably be fine.

If for whatever reason the thread does switch on you, the mutex will be treated as abandoned and any other thread can acquire it (WaitOne()) at that point.

asp.net mvc 4 - Okay to share DbContext per thread?

is it safe to dependency inject a DbContext instance for each thread?

It depends. If your idea is to have one DbContext per web request, and the consistency of your application depends on it, having one DbContext per thread is a bad idea, since a single web request can still get multiple DbContext instances. And since ASP.NET pools threads, instances that are cached per thread, will live for the duration of the entire application, which is very bad for a DbContext (as explained here).

On the other hand, you might be able to come up with a caching scheme that ensures that a single DbContext is used for a single web request, and is returned to a pool when the request is finished, so other web requests could pick it up. This is basically the way how connection pooling in .NET works. But since DbContext instances cache data, that data becomes stale very quickly, so even if you are able to come up with a thread-safe solution, your system still behaves in an inconsistent way, since at some seemingly random moments, old data is shown to the user, while in a following request new data is shown.

I think it is possible to clear the DbContext's cache at the beginning of a web request, but that would be basically be the same as creating a new DbContext for that request, but with the downside of much slower performance.

I'm just wondering if it is safe and sufficient to use PerThreadLifetimeManager.

No, it isn't safe because of the reasons described above.

But it is actually quite easy to register a DbContext on a per-web request basis:

container.Register<MyApplicationEntities>(new InjectionFactory(c => {
var context = (MyApplicationEntities)HttpContext.Current.Items["__dbcontext"];

if (context == null) {
context = new MyApplicationEntities();
HttpContext.Current.Items["__dbcontext"] = context;
}

return context;
}));

CallContext vs ThreadStatic

Very often a request will use the same thread throughout, but it certainly won't always be the case - ASP.NET exhibits thread agility. There's an old in-depth blog article about the matter from 2005, but as of .NET 4.5 things are rather better.



Related Topics



Leave a reply



Submit