How to prevent a class from being used in another thread - c#

I have a class that I want to use only in one thread. If I create an object of the class in one thread and use it in another, it will cause lots of problems. Currently, I resolve this problem like this:
I have Context class and I want to use it only in one thread:
public class Context
{
public Thread CreatedThread { get; }
public Context()
{
CreatedThread = Thread.CurrentThread;
}
public void AssertThread()
{
if (CreatedThread != Thread.CurrentThread)
{
throw new InvalidOperationException("Use only one thread!");
}
}
//Lot of properties and methods here
}
And here is the usage of Context class in Student class:
public class Student
{
Context context;
public Context Context
{
get
{
if (context == null)
context = new Context();
context.AssertThread();
return context;
}
}
}
And when I use context in a different thread, it will throw an error:
var student = new Student();
var context = student.Context;
Task.Run(() =>
{
var context = student.Context;//InvalidOperationException
});
But this solution is not reliable. For example, when I have another class that uses context, I need to do AssertThread on getting context property. Or when I get the context in a new variable and use it in a different thread, my exception will not be thrown. So, is there any solution to enforce class being used only in one thread?

AFAIK neither the C# language nor the standard .NET APIs provide a way to embed automatically the AssertThread() check in the start of every public method and property of a class. If you don't like the idea of adding this check manually, and you are serious about it, you might want to search for some tool/add-on that can add automatically this check for you at compile time, like the PostSharp, Fody or alternatives.

Related

why the logical call context must be serializable?

Below is some code from a book:
public static void Main() {
// Put some data into the Main thread's logical call context
CallContext.LogicalSetData("Name", "Jeffrey");
// Initiate some work to be done by a thread pool thread
// The thread pool thread can access the logical call context data
ThreadPool.QueueUserWorkItem(state => Console.WriteLine("Name={0}", CallContext.LogicalGetData("Name")));
...
}
and the author says:
The items that you add to the logical call context must be serializable. Flowing an execution context that contains logical call context data items can hurt performance dramatically, because capturing the execution context requires serializing and deserializing all the data items.
So if I want to pass a custom class instance to the call context, the code has to be like:
public static void Main() {
// Put some data into the Main thread's logical call context
CallContext.LogicalSetData("Name", new Person());
// Initiate some work to be done by a thread pool thread
// The thread pool thread can access the logical call context data
ThreadPool.QueueUserWorkItem(state => Console.WriteLine("Name={0}", CallContext.LogicalGetData("Name")));
...
}
[Serializable]
class Person {
...
}
So the Person class has to be serializable (uses the Serializable attribute on top of it).
But why execution context is designed to serialize and deserialize data items? Why it is not to be designed just like passing a reference parameter to a fuction? In this way, execution context doesn't need to serialize and deserialize objects since they already exists in heap, so all execution context needs is just the reference of these objects?
There is no requirement for the payload to be serializable; the following works fine:
using System;
using System.Runtime.Remoting.Messaging;
using System.Threading;
static class P
{
public static void Main()
{
// Put some data into the Main thread's logical call context
CallContext.LogicalSetData("Name", new Person("Fred"));
// Initiate some work to be done by a thread pool thread
// The thread pool thread can access the logical call context data
ThreadPool.QueueUserWorkItem(
_ => Console.WriteLine("Name={0}", CallContext.LogicalGetData("Name")));
Console.ReadLine();
}
}
class Person // note: not [Serializable]
{
public string Name { get; }
public Person(string name) => Name = name;
public override string ToString() => Name;
}
Ultimately, the System.Runtime.Remoting.Messaging.CallContext API was designed with additional requirements in mind, in particular: remoting. Since that doesn't apply here, quite simply: don't use that API. The most appropriate API for your example would seem to be AsyncLocal<T>, which provides an abstraction over the same concept:
using System;
using System.Threading;
static class P
{
private static readonly AsyncLocal<Person> s_name = new();
public static void Main()
{
// Put some data into the async-local state
s_name.Value = new Person("Jeffrey");
// Initiate some work to be done by a thread pool thread
// The thread pool thread can access the async-local state
ThreadPool.QueueUserWorkItem(
_ => Console.WriteLine($"Name={s_name.Value.Name}"));
Console.ReadLine(); // keep process alive
}
class Person // note: not [Serializable]
{
public string Name { get; }
public Person(string name) => Name = name;
}
}

Alternative To Multiple using Blocks

In all the examples I see for Entity Framework data access, every method has its own using block, as shown below.
Is there an alternative to this approach? For example, can the context object just be a class member, such as:
MyModelContext context = new MyModelContext();
Is there a reason why a new context object has to be created for each method in the DAO class?
public class DaoClass
{
public void DoSomething()
{
using (var context = new MyModelContext())
{
// Perform data access using the context
}
}
public void DoAnotherThing()
{
using (var context = new MyModelContext())
{
// Perform data access using the context
}
}
public void DoSomethingElse()
{
using (var context = new MyModelContext())
{
// Perform data access using the context
}
}
}
You could have the DaoClass implement IDisposable and have the context be a property of the class. Just make sure to wrap DaoClass in a using statement or call Dispose() on the instance of the DaoClass.
public class DaoClass : IDisposable
{
MyModelContext context = new MyModelContext();
public void DoSomething()
{
// use the context here
}
public void DoAnotherThing()
{
// use the context here
}
public void DoSomethingElse()
{
// use the context here
}
public void Dispose()
{
context.Dispose();
}
}
Please note that the context object is the equivalent to a database transaction.
It implements the IDisposable interface because a transaction must be closed when done with and you either have to use the using statement or make an implementation of IDisposable like Lews Therin demonstrated.
We use multiple instances of a context object to separate different transactions. There will be cases when you want all changes to go as a single transaction and either commit all together or rollback everything. Then you put it all in one context instance. But there will also be cases where you want to separate the saving of one data pack from another. Then you use different transactions, i.e. different context objects.
To get a better grasp of this chapter take a look at the unit of work pattern.
Hope I could help, merry coding!
The way you show it is how I've seen it recommended everywhere. I've seen there be weird issues with class level declaration returning stale or incorrect data.
To get around duplicating all the code I like to write an execute method that I can reuse, or make changes without having to go to every using.
private T Execute<T>(Func<MyModelContext, T> function)
{
using (MyModelContext ctx = new MyModelContext())
{
var result = function(ctx);
ctx.SaveChanges();
return result;
}
}
public List<Type> GetTypes()
{
return Execute((ctx) =>
{
return ctx.Types.ToList();
});
}

ASP.NET Core dependency injection: Service resolved at runtime using a Func delegate

I'm trying to inject a service to my controllers but I want to inject a different instance of my service depending of several parameters. Actually for this part it's working, I'm able to do it.
What I want is to load a specific instance of IRepository<Database> based on some configuration we get from a configuration file and respecting the DRY rule (don't repeat yourself).
I have these 2 classes:
public abstract class FooServicesProvider
{
public Func<IServiceProvider, IRepository<Database>> DatabaseRepository = provider =>
{
return null;
};
}
public class FooFileSystemServicesProvider : FooServicesProvider
{
public new Func<IServiceProvider, IRepository<Database>> DatabaseRepository = provider =>
{
//Specific code determining which database to use and create a new one if needed
//our databases are FOLDERS containing some files
//knowing how chosenDb.FullName is set is not important here
//[...]
var databaseRepository = new DatabaseFileSystemRepository(chosenDb.FullName);
databaseRepository.testProperty = "Foo value";
return databaseRepository;
};
}
Notice the new keyword used to redefine the code of my Func. This is the best way I found because of the Func delegate, I'm very limited, I can't use it in an Interface neither override it.
Now in my ConfigureServices method in Startup.cs I have this code
var fakeConfiguration = "File";
FooServicesProvider servicesProvider = null;
if(fakeConfiguration == "File")
{
servicesProvider = new FooFileSystemServicesProvider();
}
else
{
servicesProvider = new AnotherFooServicesProvider();
}
//Here is the tricky part
//This should call FooFileSystemServicesProvider.DatabaseRepository because of the "new" keyword, but it's NOT
services.AddScoped<IRepository<Database>>(servicesProvider.DatabaseRepository);
My problem is that the new keyword is ignored at runtime and the executed Func is the one declared in my base class instead of the derived one.
If I do this it's working
services.AddScoped<IRepository<Database>>((servicesProvider as FooFileSystemServicesProvider).DatabaseRepository);
But I don't want to cast it as I can't know of which type my servicesProvider will finally be.
I've tried to get the type of my servicesProvider and cast it with its own type but I get compiler error because a Type variable and a Class are different.
So how can I get the good Func executed at runtime? Thanks
Ok so I finally managed to do what I want, it was actually not that hard, my main problem was to handle the fact that my Func was not a method but a delegate. I'm not used to deal with this variable type.
My code in Startup.cs remains unchanged but here is the new code of my custom ServicesProvider
public abstract class FooServicesProvider
{
public Func<IServiceProvider, IRepository<Database>> DatabaseRepository { get; protected set; }
}
public class FooFileSystemServicesProvider : FooServicesProvider
{
public FooFileSystemServicesProvider()
{
base.DatabaseRepository = GetDatabaseRepository;
}
private DatabaseFileSystemRepository GetDatabaseRepository(IServiceProvider serviceProvider)
{
//Specific code determining which database to use and create a new one if needed
//our databases are FOLDERS containing some files
//knowing how chosenDb.FullName is set is not important here
//[...]
var databaseRepository = new DatabaseFileSystemRepository(chosenDb.FullName);
databaseRepository.testProperty = "Foo value";
return databaseRepository;
}
}
Just in case people are wondering: DatabaseFileSystemRepository is a class that implements the interface IRepository<Database>>
If anyone comes up with a different solution, I'm very curious to know it.

How to share the same context with different threads in multi-Command Pattern in C#?

There is an extended implementation of command pattern to support multi-commands (groups) in C#:
var ctx= //the context object I am sharing...
var commandGroup1 = new MultiItemCommand(ctx, new List<ICommand>
{
new Command1(ctx),
new Command2(ctx)
});
var commandGroup2 = new MultiItemCommand(ctx, new List<ICommand>
{
new Command3(ctx),
new Command4(ctx)
});
var groups = new MultiCommand(new List<ICommand>
{
commandGroup1 ,
commandGroup2
}, null);
Now , the execution is like:
groups.Execute();
I am sharing the same context (ctx) object.
The execution plan of the web app needs to separate
commandGroup1 and commandGroup2 groups in different thread. In specific, commandGroup2 will be executed in a new thread and commandGroup1 in the main thread.
Execution now looks like:
//In Main Thread
commandGroup1.Execute();
//In the new Thread
commandGroup2.Execute();
How can I thread-safely share the same context object (ctx), so as to be able to rollback the commandGroup1 from the new Thread ?
Is t.Start(ctx); enough or do I have to use lock or something?
Some code implementation example is here
The provided sample code certainly leaves open a large number of questions about your particular use-case; however, I will attempt to answer the general strategy to implementing this type of problem for a multi-threaded environment.
Does the context or its data get modified in a coupled, non-atmoic way?
For example, would any of your commands do something like:
Context.Data.Item1 = "Hello"; // Setting both values is required, only
Context.Data.Item2 = "World"; // setting one would result in invalid state
Then absolutely you would need to utilize lock(...) statements somewhere in your code. The question is where.
What is the thread-safety behavior of your nested controllers?
In the linked GIST sample code, the CommandContext class has properties ServerController and ServiceController. If you are not the owner of these classes, then you must carefully check the documentation on the thread-safety of of these classes as well.
For example, if your commands running on two different threads perform calls such as:
Context.ServiceController.Commit(); // On thread A
Context.ServiceController.Rollback(); // On thread B
There is a strong possibility that these two actions cannot be invoked concurrently if the creator of the controller class was not expecting multi-threaded usage.
When to lock and what to lock on
Take the lock whenever you need to perform multiple actions that must happen completely or not at all, or when invoking long-running operations that do not expect concurrent access. Release the lock as soon as possible.
Also, locks should only be taken on read-only or constant properties or fields. So before you do something like:
lock(Context.Data)
{
// Manipulate data sub-properties here
}
Remember that it is possible to swap out the object that Data is pointing to. The safest implementation is to provide a special locking objects:
internal readonly object dataSyncRoot = new object();
internal readonly object serviceSyncRoot = new object();
internal readonly object serverSyncRoot = new object();
for each sub-object that requires exclusive access and use:
lock(Context.dataSyncRoot)
{
// Manipulate data sub-properties here
}
There is no magic bullet on when and where to do the locks, but in general, the higher up in the call stack you put them, the simpler and safer your code will probably be, at the expense of performance - since both threads cannot execute simultaneously anymore. The further down you place them, the more concurrent your code will be, but also more expense.
Aside: there is almost no performance penalty for the actual taking and releasing of the lock, so no need to worry about that.
Assume we have a MultiCommand class that aggregates a list of ICommands and at some time must execute all commands Asynchronously. All Commands must share context. Each command could change context state, but there is no set order!
The first step is to kick off all ICommand Execute methods passing in the CTX. The next step is to set up an event listener for new CTX Changes.
public class MultiCommand
{
private System.Collections.Generic.List<ICommand> list;
public List<ICommand> Commands { get { return list; } }
public CommandContext SharedContext { get; set; }
public MultiCommand() { }
public MultiCommand(System.Collections.Generic.List<ICommand> list)
{
this.list = list;
//Hook up listener for new Command CTX from other tasks
XEvents.CommandCTX += OnCommandCTX;
}
private void OnCommandCTX(object sender, CommandContext e)
{
//Some other task finished, update SharedContext
SharedContext = e;
}
public MultiCommand Add(ICommand cc)
{
list.Add(cc);
return this;
}
internal void Execute()
{
list.ForEach(cmd =>
{
cmd.Execute(SharedContext);
});
}
public static MultiCommand New()
{
return new MultiCommand();
}
}
Each command handles the asynchronous part similar to this:
internal class Command1 : ICommand
{
public event EventHandler CanExecuteChanged;
public bool CanExecute(object parameter)
{
throw new NotImplementedException();
}
public async void Execute(object parameter)
{
var ctx = (CommandContext)parameter;
var newCTX = await Task<CommandContext>.Run(() => {
//the command context is here running in it's own independent Task
//Any changes here are only known here, unless we return the changes using a 'closure'
//the closure is this code - var newCTX = await Task<CommandContext>Run
//newCTX is said to be 'closing' over the task results
ctx.Data = GetNewData();
return ctx;
});
newCTX.NotifyNewCommmandContext();
}
private RequiredData GetNewData()
{
throw new NotImplementedException();
}
}
Finally we set up a common event handler and notification system.
public static class XEvents
{
public static EventHandler<CommandContext> CommandCTX { get; set; }
public static void NotifyNewCommmandContext(this CommandContext ctx, [CallerMemberName] string caller = "")
{
if (CommandCTX != null) CommandCTX(caller, ctx);
}
}
Further abstractions are possible in each Command's execute function. But we won't discuss that now.
Here's what this design does and doesn't do:
It allows any finished task to update the new context on the thread it was first set in the MultiCommand class.
This assumes there is no workflow based state necessary. The post merely indicated a bunch of task only had to run asynchronous rather than in an ordered asynchronous manner.
No currencymanager is necessary because we are relying on each command's closure/completion of the asynchronous task to return the new context on the thread it was created!
If you need concurrency then that implies that the context state is important, that design is similar to this one but different. That design is easily implemented using functions and callbacks for the closure.
As long as each context is only used from a single thread concurrently there is no problem with using it from multiple threads.

LINQ Changeset multi-threading

I'm using LINQ to SQL and after I submit some changes I want to spawn a thread which looks through all the changes and updates our lucene index as necessary. My code looks vaguely like:
(new Thread(() => { UpdateIndex(context.GetChangeSet()); }).Start();
Sometimes though I get an InvalidOperationException, which I think is because context.GetChangeSet() is not thread-safe, and so if the change set is modified in one thread while another thread is enumerating through it, problems arise.
Is there a "thread-safe" version of GetChangeSet()? Or some way I can do ChangeSet.clone() or something?
Instance members of the DataContext class are not thread-safe.
In order to avoid race conditions you should invoke the DataContext.GetChangeSet method from the same thread that makes the modifications tracked by the DataContext instance. For example:
public class CustomerDao : IDisposable
{
private DataContext context;
public CustomerDao()
{
this.context = new DataContext("SomeConnectionString");
}
public void Insert(Customer instance)
{
this.context.Customers.InsertOnSubmit(instance);
this.StartUpdateIndex();
this.context.SubmitChanges();
}
public void Delete(Customer instance)
{
this.context.Customers.DeleteOnSubmit(instance);
this.StartUpdateIndex();
this.context.SubmitChanges();
}
public void Dispose()
{
if (this.context != null)
{
this.context.Dispose();
}
}
private void StartUpdateIndex()
{
ChangeSet changes = this.context.GetChangeSet();
ThreadPool.QueueUserWorkItem(
state => this.UpdateIndex((ChangeSet)state), changes);
}
}
This assumes that the Insert and Delete methods are being called on a given instance of the CustomerDao class from a single thread.
I only needed to extract a small amount of data from each object, so for I ended up just extracting the text, putting it into a new object, then sending that new object off. This saved me a lot of trouble from having to deal with locking everywhere else, but I think Enrico's answer is probably the "real" one, so leaving his marked as the solution.

Categories

Resources