Thread synchronization in DI container managed instances - c#

I have a FooContext class that captures some HTTP request-specific runtime values from the request inside an ASP.NET Web API application
public class FooContext
{
private readonly ISet<string> _set = new HashSet<string>();
public void AddToSet(string s) => _set.Add(s);
// Copied so that caller won't modify _set
public ISet<string> GetStrings() => new HashSet<string>(_set);
}
Multiple consumers depends on this FooContext and will call AddToSet/GetStrings and depending on the result, run different business logic.
I want to guarantee there will only be one instance per of FooContext per HTTP request so I registered inside the DI container as request-scoped (using Autofac here as an example but I guess most containeirs are roughly the same):
protected override void Load(ContainerBuilder builder)
{
builder.RegisterType<FooContext>().InstancePerRequest();
}
My understanding is, FooContext is not thread-safe because threads may call GetStrings/AddToSet at the same time on the same FooContext instance (since it is request-scoped). It is not guaranteed that each HTTP request will complete on one single thread.
I do not explictly create new threads nor call Task.Run() in my application but I do use a lot of async-await with ConfigureAwait(false), which means the continuation may be on a different thread.
My questions are:
Is it true that FooContext is not thread-safe? Is my understanding above correct?
If this is indeed thread unsafe, and I want to allow multiple readers but only one exclusive writer, should I apply a ReaderWriterLockSlim on the ISet<string>?
Update
Since a commenter comments that my question is unanswerable without showing FooContext's usage, I will do it here. I use FooContext in an IAutofacActionFilter to capture several parameters that are being passed in the controller method:
public class FooActionFilter : IAutofacActionFilter
{
private readonly FooContext _fooContext;
public FooActionFilter(FooContext fooContext)
=> _fooContext = fooContext;
public Task OnActionExecutingAsync(
HttpActionContext actionContext,
CancellationToken cancellationToken)
{
var argument = (string)actionContext.ActionArguments["mystring"];
_fooContext.AddToSet(argument);
return Task.CompletedTask;
}
}
Then in other service classes that control business logic:
public class BarService
{
private readonly FooContext _fooContext;
public BarService(FooContext fooContext)
=> _fooContext = fooContext;
public async Task DoSomething()
{
var strings = _fooContext.GetStrings();
if (strings.Contains("foo"))
{
// Do something
}
}
}

It is not guaranteed that each HTTP request will complete on one single thread.
When using async/await, the request might run on multiple threads, but the request will flow from one thread to the other, meaning that the request will not run on multiple threads in parallel.
This means that the classes that you cache on a per-request basis don't have to be thread-safe, since their state is not accessed in parallel. They do need to be able to be accessed from multiple threads sequentially though, but this is typically only a problem if you start storing thread-ids, or any other thread-affinit state (using ThreadLocal<T> for instance).
So don't do any special synchronization or use any concurrent data structures (such as ConcurrentDictionary), because it will only complicate your code, while this is not needed (unless you forget to await for some operation, because in that case you will accidentally run operations in parallel, which can cause all sorts of problems. Welcome to beautiful world of async/await).
Multiple consumers depends on this FooContext and will call AddToSet/GetStrings and depending on the result, run different business logic.
Those consumers can depend on FooContext as long as they have a lifetime that is either Transient or InstancePerRequest. And this holds for their consumers all the way up the call graph. If you violate this rule, you will have a Captive Dependency, which may cause your FooContext instance to be reused by multiple requests, which will cause concurrency problems.
You do have to take some care when working with DI in multi-threaded applications though. This documentation does give some pointers.

I do not explictly create new threads nor call Task.Run() in my application but I do use a lot of async-await with ConfigureAwait(false), which means the continuation may be on a different thread.
Yes, so it is being accessed in a multithreaded fashion.
Is it true that FooContext is not thread-safe? Is my understanding above correct?
Yes.
I would say that the calling code is actually in error: ConfigureAwait(false) means "I don't need the request context", but if the code uses FooContext (part of the request context), then it does need the request context.
If this is indeed thread unsafe, and I want to allow multiple readers but only one exclusive writer, should I apply a ReaderWriterLockSlim on the ISet?
Almost certainly not. A lock would probably work just fine.
Using reader/writer locks just because some code does reads and other does writes is a common mistake. Reader/writer locks are only necessary when some code does reads, other does writes, and there is a significant amount of concurrent read access.

Related

What is the proper way to stop awaited tasks when object goes out of scope?

My application has two distinct states, each of them having independent set of resources, but only one of them can be active at a time.
The state is represented by a class which holds managed references to various services. For simplicity let's just assume this:
class FirstApplicationState {
ServiceA FooService { get; }
ServiceB BarService { get; }
}
// Some 'global' object holds reference to State
Application.State = new FirstApplicationState();
The ServiceA class during execution launches a delayed-execution task.
class ServiceA {
CancellationTokenSource tsc;
private async Task TriggerDelayedActionAsync() {
try {
tsc = new CancellationTokenSource();
await Task.Delay(TimeSpan.FromMinutes(1),tsc.Token);
}
catch(TaskCancelledException) {
Log.Info("Task cancelled");
return;
}
finally { /*dispose tsc*/ }
await RunVeryLongTaskAsync();
}
}
The task should no longer execute if the FirstApplicationState is no longer the active state of the application. If the state will go out of scope and the entire hierarchy will be marked to be colleced by invoking Application.State = null while the Task.Delay() method is being awaited, the instance of ServiceA won't be marked for GC collection, and the await will finally execute, invoking the RunVeryLongTaskAsync method, which will load some resources and potentially throw an exception.
To avoid it, the natural solution would be to just introduce some Deinitialize() method to services and run a deinitialization process which will properly trigger all cancellation tokens before the Application allows for marking state for GC collection, although it seems like requiring tracking cancellation tokens for all potential tasks.
I'm wondering if there is some other mechanism, which would let me cancel all tasks once object executing them goes out of scope? While not relying on it for proper state cleanup, maybe I can check if any tasks on entire hierarchy of objects are still running for debugging purposes? I'm also considering using double-source cancellation tokens which would allow me for some higher level cancellation like described in Microsoft's docs, but I'm not sure how common of a practice is this as I haven't encountered similar solutions before.
The task should no longer execute if the FirstApplicationState is no longer the active state of the application.
The easiest way to check this is to have the method itself check if it is still supposed to run. If you only need to check once at a particular point, that is what I would recommend.
the instance of ServiceA won't be marked for GC collection... maybe I can check if any tasks on entire hierarchy of objects are still running for debugging purposes?
There actually is no "hierarchy". The problem is that tasks exist in memory linked in the opposite way of what you need. The task returned from TriggerDelayedActionAsync does not reference the task returned from Task.Delay at all. The opposite is actually true. The timer acts as a GC root, referencing the task returned from Task.Delay, which has a continuation for TriggerDelayedActionAsync, which references the task returned from TriggerDelayedActionAsync.
To avoid it, the natural solution would be to ... trigger all cancellation tokens... although it seems like requiring tracking cancellation tokens for all potential tasks.
Yes. If you need to only check once (e.g., before the long task begins), then you can get away with a single check at that time. But if you need to be able to cancel at any time, then a CancellationToken would be an appropriate solution. Linked cancellation tokens may also be necessary, as you noted.
There's nothing built-in for this; you'll have to add those cancellation tokens everywhere if you need to support that.
If you want to list tasks for debugging purposes, you can use
TaskScheduler.GetScheduledTasks (You can get the default scheduler from Scheduler.ThreadPool)
Or implement your own TaskScheduler and use it in a TaskFactory

Is this immutable object threadsafe?

I have a class which loads some data from a server and transforms it. The class contains a method that reloads this data from the server.
I'm not sure if the reload is threadsafe, but I read that i might need to add a volatile keyword or using locks.
public class Tenants : ITenants
{
private readonly string url = "someurl";
private readonly IHttpClientFactory httpClientFactory;
private ConfigParser parser;
public Tenants(IHttpClientFactory httpClientFactory)
{
this.httpClientFactory = httpClientFactory;
}
public async Task Refresh()
{
TConfig data = await ConfigLoader.GetData(httpClientFactory.CreateClient(), url);
parser = new ConfigParser(data);
}
public async Task<TConfig> GetSettings(string name)
{
if (parser == null)
await Refresh();
return parser.GetSettings(name);
}
}
public class ConfigParser
{
private readonly ImmutableDictionary<string, TConfig> configs;
public ConfigParser(TConfig[] configs)
{
this.configs = configs.ToImmutableDictionary(s => s.name, v => v);
}
public TConfig GetSettings(string name)
{
if (!configs.ContainsKey(name))
{
return null;
}
return configs[name];
}
}
The Tenants class will be injected as a singleton intoother classes via DI IOC.
I think that this design makes this threadsafe.
It is fully atomic, and immutable with no exposed members to be changed by any consuming code. (TConfig is also immutable)
I also dont think i need a lock, if 2 threads try to set the reference at the same time, last one wins, which i am happy with.
And i dont know enough to understand if i need volatile. But from what i understood about it, i wont need it, as there is only 1 reference if parser that i care about, and its never exposed outside this class.
But i think some of my statements/assumptions above could be wrong.
EDIT:
From your comments I can deduce that you do not understand the difference between immutable and thread safety.
Immutability means an instance of an object can not be mutated (it's internal or external state can not change).
Thread safe means multiple threads can access the class/method without causing errors like race conditions, deadlocks or unexpected behavior like something which has to be executed only once is executed twice.
Immutable objects are thread safe, but something doesn't have to be immutable to be thread safe.
Your Tenants class is neither immutable nor thread safe because:
It's internal sate can change after instantiation.
It contains unexpected behavior where the request to receive the config is executed twice, where it should only happen once.
If you read my answer below you can determine that if you are ok with the request happening twice (which you shouldn't be): You don't have to do anything, but you could add the volatile keyword to the parser field to prevent SOME scenarios, but definitely not all.
You don't see any locks in immutable objects because there's no writing happening to the state of the object.
When there are writing operations in an object it is not immutable anymore (like your Tenants class). To make an object like that thread safe, you need to lock the write operations that can cause errors like the unexpected behavior of something which has to be executed only once is executed twice.
ConfigParser Seems to be thread safe, Tenants however definitely isn't.
Your Tenants class is also not immutable, since it exposes a method which changes the state of the class (both the GetSettings and Refresh methods).
If 2 threads call GetSettings at the same time when parser is null, 2 requests will be made to receive the ConfigParser. You can be OK with this, but it is bad practice, and also means the method is not thread safe.
If you are fine with the request being executed twice you could use volatile here:
The volatile keyword indicates that a field might be modified by multiple threads that are executing at the same time. The compiler, the runtime system, and even hardware may rearrange reads and writes to memory locations for performance reasons. Fields that are declared volatile are not subject to these optimizations. Adding the volatile modifier ensures that all threads will observe volatile writes performed by any other thread in the order in which they were performed.
Volatile will prevent threads from having outdated values. This means you could prevent some of the extra requests happening (from the threads which still think parser is null), but it will not completely prevent an method or instruction from being executed multiple times at the same time.
In this situation you need to lock:
The lock statement acquires the mutual-exclusion lock for a given object, executes a statement block, and then releases the lock. While a lock is held, the thread that holds the lock can again acquire and release the lock. Any other thread is blocked from acquiring the lock and waits until the lock is released.
Meaning you can prevent multiple threads from executing an method or instruction multiple times at the same time.
Unfortunately, you can't use await inside a lock.
What you want to do is:
If Refresh needs to be called:
If another thread is already working on the Refresh
Wait for the other thread to finish, and do not call Refresh
Continue with the result from the other thread
if no other thread is already working on the Refresh
Invoke the Refresh method
I have written a library for this called TaskSynchronizer. You can use that to accomplish a true thread safe version of you Tenants class.
Example:
public static TaskSynchronizer Synchronizer = new TaskSynchronizer();
public static async Task DoWork()
{
await Task.Delay(100); // Some heavy work.
Console.WriteLine("Work done!");
}
public static async Task WorkRequested()
{
using (Synchronizer.Acquire(DoWork, out var task)) // Synchronize the call to work.
{
await task;
}
}
static void Main(string[] args)
{
var tasks = new List<Task>();
for (var i = 0; i < 2; i++)
{
tasks.Add(WorkRequested());
}
Task.WaitAll(tasks.ToArray());
}
will output:
Work done!
EG: The async DoWork method has only be invoked once, even tho it has been invoked twice at the same time.

How to check that AsyncLocal<T> is accessed within same "async context"

TL;DR ThreadLocal<T>.Value points to same location if Thread.CurrentThread stays the same. Is there anything similar for AsyncLocal<T>.Value (e.g. would SychronizationContext.Current or ExecutionContext.Capture() suffice for all scenarios)?
Imagine we have created some snapshot of data structure which is kept in thread-local storage (e.g. ThreadLocal<T> instance) and passed it to axillary class for later use. This axillary class is used to restore this data structure to snapshot state. We don't want to restore this snapshot onto different thread, so we can check on which thread axillary class was created. For example:
class Storage<T>
{
private ThreadLocal<ImmutableStack<T>> stackHolder;
public IDisposable Push(T item)
{
var bookmark = new StorageBookmark<T>(this);
stackHolder.Value = stackHolder.Value.Push(item);
return bookmark;
}
private class StorageBookmark<TInner> :IDisposable
{
private Storage<TInner> owner;
private ImmutableStack<TInner> snapshot;
private Thread boundThread;
public StorageBookmark(Storage<TInner> owner)
{
this.owner = owner;
this.snapshot = owner.stackHolder.Value;
this.boundThread = Thread.CurrentThread;
}
public void Dispose()
{
if(Thread.CurrentThread != boundThread)
throw new InvalidOperationException ("Bookmark crossed thread boundary");
owner.stackHolder.Value = snapshot;
}
}
}
With this, we essentialy bound StorageBookmark to specific thread, and, therefore, to specific version of data structure in ThreadLocal storage. And we did that by assuring we don't cross "thread context" with the help of Thread.CurrentThread
Now, to question at hand. How can we achieve the same behavior with AsyncLocal<T> instead of ThreadLocal<T>? To be precise, is there anything similar to Thread.CurrentThread which can be checked at times of construction and usage to control that "async context" has not been crossed (That means AsyncLocal<T>.Value would point to same object as when bookmark was constructed).
It seems either SynchronizationContext.Current or ExecutionContext.Capture() may suffice, but I'm not sure which is better and that there is no catch (or even that would work in all possible situations)
What you're hoping to do is fundamentally contrary to the nature of asynchronous execution context; you're not required to (and therefore can't guarantee) that all Tasks created within your asynchronous context will be awaited immediately, in the same order they were created, or ever at all, but their creation within the scope of the calling context makes them part of the same asynchronous context, period.
It may be challenging to think of asynchronous execution context as different from thread contexts, but asynchrony is not synonymous with parallelism, which is specifically what logical threads support. Objects stored in Thread Local Storage that aren't intended to be shared/copied across threads can generally be mutable because execution within a logical thread will always be able to guarantee relatively constrained sequential logic (if some special treatment may be necessary to ensure compile-time optimizations don't mess with you, though this is rare and only necessary in very specific scenarios). For that reason the ThreadLocal in your example doesn't really need to be an ImmutableStack, it could just be a Stack (which has much better performance) since you don't need to worry about copy-on-write or concurrent access. If the stack were publicly accessible then it would be more concerning that someone could pass the stack to other threads which could push/pop items, but since it's a private implementation detail here the ImmutableStack could actually be seen as unnecessary complexity.
Anyway, Execution Context, which is not a unique concept to .NET (implementations on other platforms may differ in some ways, though in my experience never by much) is very much like (and directly related to) the call stack, but in a way that considers new asynchronous tasks to be new calls on the stack which may need to both share the caller's state as it was at the time the operation was executed, as well as diverge since the caller may continue to create more tasks and create/update state in ways that will not make logical sense when reading a sequential set of instructions. It is generally recommended that anything placed in the ExecutionContext be immutable, though in some cases all copies of the context still pointing to the same instance reference should necessarily share mutable data. IHttpContext, for instance, is stored on the default implementation of IHttpContextAccessor using AsyncLocal, so all tasks created in the scope of a single request will have access to the same response state, for example. Allowing multiple concurrent contexts to make mutations to the same reference instance necessarily introduces the possibility of issues, both from concurrency and logical order of execution. For instance, multiple tasks trying to set different results on an HTTP response will either result in an exception or unexpected behavior. You can try, to some extent, to help the consumer here, but at the end of the day it is the consumer's responsibility to understand the complexity of the nuanced implementation details they're dependent on (which is generally a code smell, but sometimes a necessary evil in real world situations).
That scenario aside, as said, for the sake of ensuring all nested contexts function predictably and safely it's generally recommended to only store immutable types and to always restore the context to its previous value (as you're doing with you disposable stack mechanism). The easiest way to think of the copy-on-write behavior is as though every single new task, new thread pool work item, and new thread gets its own clone of the context, but if they point to the same reference type (i.e. all have copies of the same reference pointer) they all have the same instance; the copy-on-write is simply an optimization that prevents copying when unnecessary, but can essentially be completely ignored and thought of as every logical task having its own copy of the context (which is very much like that ImmutableStack or a string). If the only way to update anything about the current value that the immutable collection item points to is to reassign it to a new modified instance then you never have to worry about cross-context pollution (just like that ImmutableStack you're using).
Your example doesn't show anything about how the data is accessed or what types are passed in for T so there's no way to see what issue you might face, but if what you're concerned about is nested tasks disposing the "Current" context or the IDisposable value being assigned to a field somewhere and accessed from a different thread, there's a few things you can try and some points worth considering:
The closest equivalent to your current check would be:
if(stackHolder.Value != this)
throw new InvalidOperationException ("Bookmark disposed out of order or in wrong context");
A simple ObjectDisposedException will throw an exception from at least one context if two contexts try to dispose it.
Though this generally isn't recommended, if you want to be absolutely certain the object was disposed at least once you could throw an exception in the finalizer of the IDisposable implementation (being sure to call GC.SuppressFinalize(this) in the Dispose method).
By combining the previous two, while it won't guarantee that it was disposed in the exact some task/method block that created it, you can at least guarantee that an object is disposed once and only once.
Due to the fundamental importance of the ways ExecutionContext is supposed to be flowed and controlled, it is the responsibility of the execution engine (typically the runtime, task scheduler, etc. but also in cases where a third party is using Tasks/Threads in novel ways) to ensure ExecutionContext flow is captured and suppressed where appropriate. If a thread, scheduler, or synchronization migration occurs in the root context, the ExecutionContext should not be flowed into the next logical task's ExecutionContext the thread/scheduler processes in the context where the task formerly executed. For example, if a task continuation starts on a ThreadPool thread and then awaits continuation that causes the next logical operations to continue on a different ThreadPool Thread than it was originally started on or some other I/O resource completion thread, when the original thread is returned the the ThreadPool it should not continue to reference/flow the ExecutionContext of the task which is no longer logically executing within it. Assuming no additional tasks are created in parallel and left astray, once execution resumes in the root awaiter it will be the only execution context that continues to have a reference to the context. When a Task completes, so does its execution context (or, rather, its copy of it).
Even if unobserved background tasks are started and never awaited, if the data stored in the AsyncLocal is immutable, the copy-on-write behavior combined with your immutable stack will ensure that parallel clones of execution contexts can never pollute each other
With the first check and used with immutable types, you really don't need to worry about cloned parallel execution contexts unless you're worried about them gaining access to sensitive data from previous contexts; when they Dispose the current item only the stack of the current execution context (e.g. the nested parallel context, specifically) reverts to the previous; all cloned contexts (including the parent) are not modified.
If you are worried about nested contexts accessing parent data by disposing things they shouldn't there are relatively simple patterns you can use to separate the IDisposable from the ambient value, as well as suppression patterns like those used in TransactionScope to, say, temporarily set the current value to null, etc.
Just to reiterate in a practical way, let's say, for instance, that you store an ImmutableList in one of your bookmarks. If the item stored in the ImmutableList is mutable then context pollution is possible.
var someImmutableListOfMutableItems = unsafeAsyncLocal.Value;
// sets Name for all contexts pointing to the reference type.
someImmutableListOfMutableItems[0].Name = "Jon"; // assigns property setter on shared reference of Person
// notice how unsafeAsyncLocal.Value never had to be reassigned?
Whereas an immutable collection of immutable items will never pollute another context unless something is super fundamentally wrong about how execution context is being flowed (contact a vendor, file a bug report, raise the alarm, etc.)
var someImmutableListOfImmutableItems = safeAsyncLocal.Value;
someImmutableListOfImmutableItems = someImmutableListOfImmutableItems.SetItem(0,
someImmutableListOfImmutableItems[0].SetName("Jon") // SetName returns a new immutable Person instance
); // SetItem returns new immutable list instance
// notice both the item and the collection need to be reassigned. No other context will be polluted here
safeAsyncLocal.Value = someImmutableListOfImmutableItems;
EDIT: Some articles for people who want to read something perhaps more coherent than my ramblings here :)
https://devblogs.microsoft.com/pfxteam/executioncontext-vs-synchronizationcontext/
https://weblogs.asp.net/dixin/understanding-c-sharp-async-await-3-runtime-context
And for some comparison, here's an article about how context is managed in JavaScript, which is single threaded but supports an asynchronous programming model (which I figure might help to illustrate how they relate/differ):
https://blog.bitsrc.io/understanding-execution-context-and-execution-stack-in-javascript-1c9ea8642dd0
The logical call context has the same flow semantics as the execution context, and therefore as AsyncLocal. Knowing that, you can store a value in the logical context to detect when you cross "async context" boundaries:
class Storage<T>
{
private AsyncLocal<ImmutableStack<T>> stackHolder = new AsyncLocal<ImmutableStack<T>>();
public IDisposable Push(T item)
{
var bookmark = new StorageBookmark<T>(this);
stackHolder.Value = (stackHolder.Value ?? ImmutableStack<T>.Empty).Push(item);
return bookmark;
}
private class StorageBookmark<TInner> : IDisposable
{
private Storage<TInner> owner;
private ImmutableStack<TInner> snapshot;
private Thread boundThread;
private readonly object id;
public StorageBookmark(Storage<TInner> owner)
{
id = new object();
this.owner = owner;
this.snapshot = owner.stackHolder.Value;
CallContext.LogicalSetData("AsyncStorage", id);
}
public void Dispose()
{
if (CallContext.LogicalGetData("AsyncStorage") != id)
throw new InvalidOperationException("Bookmark crossed async context boundary");
owner.stackHolder.Value = snapshot;
}
}
}
public class Program
{
static void Main()
{
DoesNotThrow().Wait();
Throws().Wait();
}
static async Task DoesNotThrow()
{
var storage = new Storage<string>();
using (storage.Push("hello"))
{
await Task.Yield();
}
}
static async Task Throws()
{
var storage = new Storage<string>();
var disposable = storage.Push("hello");
using (ExecutionContext.SuppressFlow())
{
Task.Run(() => { disposable.Dispose(); }).Wait();
}
}
}

Are there any side effects of using a complex object in a Montor.Enter lock?

Most code examples I've seen of locking use a pattern like this:
private static int _counter = 0;
private static readonly object _sync = new object();
public void DoWork()
{
int counter;
lock (_sync)
{
counter = _counter++;
}
// etc ...
}
My guess is that Montor.Enter uses some sort of reference pointer to the object that lives in memory to build some internal dictionary of what is locked by what thread. Not sure if this is correct, however.
I'm wondering if there are any ramifications of using a more complex object in the Monitor.Enter parameter. For example, if multiple threads were trying to broadcast to a WebSocket, it would be necessary to either
Queue up the requests and have a single thread be responsible for sending, or
Use locking to prevent multiple threads from sending to the same socket.
Suppose the WebSocket object itself was used for the lock:
public async Task SendMessage(WebSocket socket, ArraySegment<byte> data)
{
lock (socket)
{
if (socket.State == WebSocketState.Open)
{
await socket.SendAsync(
data,
WebSocketMessageType.Text,
true,
CancellationToken.None);
}
}
}
If Monitor.Enter simply uses a reference pointer to the underlying object in memory, there would theoretically be no side effects to the fact that it is a big, complex object, instead of a tiny little new object().
Does anyone have any data on this?
Edit: After some answers below, I've come up with an alternative pattern, extending the WebSocket example. Any further feedback would be appreciated.
A thin wrapper around the underlying object allows for the creation of a private readonly object to use for locking.
The async method inside the lock is made synchronous.
Note that this pattern doesn't take into account the suggestion of only allowing a single thread to have access to the WebSocket connection (through a queue system) -- I'm mostly trying to work through my understanding of a locking pattern with a specific example.
public class SocketWrapper
{
private readonly object _sync = new object();
public WebSocket Socket { get; private set; }
public SocketWrapper(WebSocket socket)
{
this.Socket = socket;
}
public async Task SendMessage(ArraySegment<byte> data)
{
await Task.Yield();
lock (this._sync)
{
var t = await this.Socket.SendAsync(
data,
WebSocketMessageType.Text,
true,
CancellationToken.None);
t.Wait();
}
}
}
The lock mechanism uses the header of the object to lock on, it doesn't matter how complex the object is because the header is what the mechanism is using. However a good rule of thumb for locks.
Most of the time should only be locking on read-only references
Create a new private object for your locks for clarity and because someone might be locking on themselves see this answer for more information
Don't make your locks static unless your Method is locking at a program level
You can read more about the lock keyword and Monitor.Enter on MSDN:
Monitor.Enter Method (Object)
https://msdn.microsoft.com/en-us/library/c5kehkcz.aspx
This is fine. .NET uses a bit of the Object header to effectively create and use a spinlock, or if that fails, it uses a pool of Semaphores.
In either case, it's based on the underlying Object header that all objects in .NET have. It doesn't matter how complex or simple the containing object is.
My guess is that Montor.Enter uses some sort of reference pointer to the object that lives in memory to build some internal dictionary of what is locked by what thread. Not sure if this is correct, however.
As others have noted, there's actually a Monitor built-into every single .NET reference type. There's not an actual "dictionary" (or any other collection) of what is held by any thread.
I'm wondering if there are any ramifications of using a more complex object in the Monitor.Enter parameter.
Using any reference type is fine. However...
multiple threads were trying to broadcast to a WebSocket
In this kind of situation, queueing is preferred. In particular, await cannot exist inside a lock. It's possible to do a kind of implicit queueing by using an async-compatible lock, but that's a whole other story.
Also, it's not recommended to lock on an argument. If this example was synchronous, it would still be not recommended:
// NOT recommended
public void SendMessage(WebSocket socket, ArraySegment<byte> data)
{
lock (socket)
...
}
There are some lock guidelines that have developed over the years:
Locks should be private. Since any code can take a lock, as soon as you lock an instance that is accessible by any other code, you open up the possibility of a deadlock. Note that it is the privacy that is important in this rule, so lock(this) is generally understood to be "not recommended", but the reason is not because you "shouldn't lock this", but rather because "this is not private, and you should only lock private instances".
Never call arbitrary code while holding a lock. This includes raising events or invoking callbacks. Again, this opens up the possibility of a deadlock.
The code within a lock (in a "critical section") should be as short as possible.
It's generally best to have an explicit "mutex" object (i.e., _sync), for code readability and maintainability.
The "mutex" should be documented as to what other object(s) it is protecting.
Avoid code that needs to take multiple locks. If this is unavoidable, establish and document a lock hierarchy so that locks are always acquired in the same order.
These rules naturally result in the common mutex code:
private readonly object _sync = new object();

How to force multiple commands to execute in same threading timeslice?

I have a C# app that needs to do a hot swap of a data input stream to a new handler class without breaking the data stream.
To do this, I have to perform multiple steps in a single thread without any other threads (most of all the data recieving thread) to run in between them due to CPU switching.
This is a simplified version of the situation but it should illustrate the problem.
void SwapInputHandler(Foo oldHandler, Foo newHandler)
{
UnhookProtocol(oldHandler);
HookProtocol(newHandler);
}
These two lines (unhook and hook) must execute in the same cpu slice to prevent any packets from getting through in case another thread executes in between them.
How can I make sure that these two commands run squentially using C# threading methods?
edit
There seems to be some confusion so I will try to be more specific. I didn't mean concurrently as in executing at the same time, just in the same cpu time slice so that no thread executes before these two complete. A lock is not what I'm looking for because that will only prevent THIS CODE from being executed again before the two commands run. I need to prevent ANY THREAD from running before these commands are done. Also, again I say this is a simplified version of my problem so don't try to solve my example, please answer the question.
Performing the operation in a single time slice will not help at all - the operation could just execute on another core or processor in parallel and access the stream while you perform the swap. You will have to use locking to prevent everybody from accessing the stream while it is in an inconsistent state.
Your data receiving thread needs to lock around accessing the handler pointer and you need to lock around changing the handler pointer.
Alternatively if your handler is a single variable you could use Interlocked.Exchange() to swap the value atomically.
Why not go at this from another direction, and let the thread in question handle the swap. Presumably, something wakes up when there's data to be handled, and passes it off to the current Foo. Could you post a notification to that thread that it needs to swap in a new handler the next time it wakes up? That would be much less fraught, I'd think.
Okay - to answer your specific question.
You can enumerate through all the threads in your process and call Thread.Suspend() on each one (except the active one), make the change and then call Thread.Resume().
Assuming your handlers are thread safe, my recommendation is to write a public wrapper over your handlers that does all the locking it needs using a private lock so you can safely change the handlers behind the scenes.
If you do this you can also use a ReaderWriterLockSlim, for accessing the wrapped handlers which allows concurrent read access.
Or you could architect your wrapper class and handler clases in such a way that no locking is required and the handler swamping can be done using a simple interlocked write or compare exchange.
Here's and example:
public interface IHandler
{
void Foo();
void Bar();
}
public class ThreadSafeHandler : IHandler
{
ReaderWriterLockSlim rwLock = new ReaderWriterLockSlim();
IHandler wrappedHandler;
public ThreadSafeHandler(IHandler handler)
{
wrappedHandler = handler;
}
public void Foo()
{
try
{
rwLock.EnterReadLock();
wrappedHandler.Foo();
}
finally
{
rwLock.ExitReadLock();
}
}
public void Bar()
{
try
{
rwLock.EnterReadLock();
wrappedHandler.Foo();
}
finally
{
rwLock.ExitReadLock();
}
}
public void SwapHandler(IHandler newHandler)
{
try
{
rwLock.EnterWriteLock();
UnhookProtocol(wrappedHandler);
HookProtocol(newHandler);
}
finally
{
rwLock.ExitWriteLock();
}
}
}
Take note that this is still not thread safe if atomic operations are required on the handler's methods, then you would need to use higher order locking between treads or add methods on your wrapper class to support thread safe atomic operations (something like, BeginTreadSafeBlock() folowed by EndTreadSafeBlock() that lock the wrapped handler for writing for a series of operations.
You can't and it's logical that you can't. The best you can do is avoid any other thread from disrupting the state between those two actions (as have already been said).
Here is why you can't:
Imagine there was an block that told the operating system to never thread switch while you're on that block. That would be technically possible but will lead to starvation everywhere.
You might thing your threads are the only one being used but that's an unwise assumption. There's the garbage collector, there are the async operations that works with threadpool threads, an external reference, such as a COM object could span its own thread (in your memory space) so that noone could progress while you're at it.
Imagine you make a very long operation in your HookOperation method. It involves a lot of non leaky operations but, as the Garbage Collector can't take over to free your resources, you end up without any memory left. Or imagine you call a COM object that uses multithreading to handle your request... but it can't start the new threads (well it can start them but they never get to run) and then joins them waiting for them to finish before coming back... and therefore you join on yourself, never returning!!.
As other posters have already said, you can't enforce system-wide critical section from user-mode code. However, you don't need it to implement the hot swapping.
Here is how.
Implement a proxy with the same interface as your hot-swappable Foo object. The proxy shall call HookProtocol and never unhook (until your app is stopped). It shall contain a reference to the current Foo handler, which you can replace with a new instance when needed. The proxy shall direct the data it receives from hooked functions to the current handler. Also, it shall provide a method for atomic replacement of the current Foo handler instance (there is a number of ways to implement it, from simple mutex to lock-free).

Categories