C# threading and synchronization
Only a single thread at a time may acquire the lock, so this state is exclusive for all threads on a single lock instance. So in your example, only one method body may be executing at any given time for all instances of class Synchronization
as your lock is static. If you want locking per instance of your class, then do not mark the lock object as static.
Your assumptions regarding synchronization are correct.
Please note that you should mark the lock object readonly
for a completely water-tight solution. As the code stands, it would be possible for the lock object to be re-assigned and so break the locking semantics, e.g.:
public class Synchronization
{
private static object _lock = new object();
public void MethodA()
{
lock (_lock)
{
Console.WriteLine("I shouldn't execute with MethodB");
}
}
public void MethodB()
{
//This shouldn't be allowed!
_lock = new object();
lock (_lock)
{
Console.WriteLine("I shouldn't execute with MethodA");
}
}
}
Lock object should be marked as readonly
, i.e.:
private static readonly object _lock = new object();
thread synchronization c#
The call of Monitor.Enter
and Monitor.Exit
must be done by thread themselves. In your code, this is done by the main thread in the process of setting up the two threads. Moreover, that needs to be a monitor of the same object, not two different objects like it is in your case.
To fix this, you need to move the Enter
/Exit
onto the thread into the delegate, and add a common object for the monitor, like this:
object mon = new object();
Thread t = new Thread(()=>{
Monitor.Enter(mon);
Met1(x);
Monitor.Exit(mon);
});
Thread t2 = new Thread(()=>{
Monitor.Enter(mon);
Met2(x,y);
Monitor.Exit(mon);
});
t.start();
t2.start();
Now the t
thread would not be able to call Met1
while Met2
is going, and vice versa.
Difference between manual locking and Synchronized methods
The first method is preferred because you can (and should) make _syncRoot
private. This lowers the risk of deadlocking.
The MethodImplOptions.Synchronized
is a left-over from an earlier ambitious idea that turned out to be not so good after all.
Regarding the last question: Yes, according to this blog they are functionally equivalent (but not implemented the same way). And all forms of lock(this)
are discouraged, again because of deadlock scenarios.
C# Synchronizing Threads depending on string
My first idea was to create a Dictionary with the key beeing the file and the value beeing the lock-object. But I was wondering if it would also be possible to lock the string file? Any thoughts on this?
If the strings will be created at runtime, locking on the string will not be safe. It would be better to make a dictionary of objects, and use those to lock.
That being said, you should consider using a ConcurrentDictionary<string,object>
for this dictionary, as it will prevent a race condition (or other lock) in your dictionary itself. By using GetOrAdd you can safely get the appropriate object to use for locking.
That being said, a different approach may be appropriate here. You could use a ConcurrentQueue
or BlockingCollection
to provide a list of items to process, and then have a fixed number of threads process them. This will prevent synchronization problems from occurring in the first place.
C# complex thread synchronization
Use the ReaderWriterLockSlim Class:
Represents a lock that is used to manage access to a resource,
allowing multiple threads for reading or exclusive access for writing.Use ReaderWriterLockSlim to protect a resource that is read by
multiple threads and written to by one thread at a time.
ReaderWriterLockSlim allows multiple threads to be in read mode,
allows one thread to be in write mode with exclusive ownership of the
lock, and allows one thread that has read access to be in upgradeable
read mode, from which the thread can upgrade to write mode without
having to relinquish its read access to the resource.
Joe Albahari's Threading in C# is a great resource.
Thread synchronization between UI and a worker thread
After spending most of the day trying to implement a custom SynchronizationContext
, and being fairly successful in that, I stumbled into a way of making a BlockingCollection<T>
work for my needs.
TL;DR for the posts which suggest using a BlockingCollection<T>
to ensure Actions
/delegates/methods are run on one thread, here is a boiled down (you need to add your own error handling) example:
PoorMansSynchronizier aka AutomataionActionQueue
.
public class PoorMansSynchronizier
{
private readonly BlockingCollection<Action> _queue;
private readonly Thread _thread;
public PoorMansSynchronizier(Action<Thread> options)
{
_queue = new BlockingCollection<Action>();
_thread = new Thread(() => Execute());
options?.Invoke(_thread);
if (!_thread.IsAlive) _thread.Start();
}
public void Invoke(Action action) => _queue.Add(action);
public void Complete() => _queue.CompleteAdding();
private void Execute()
{
foreach (var action in _queue.GetConsumingEnumerable())
{
action.Invoke();
}
}
}
Updated Background Worker Service
public class AutomationBackgroundWorker
{
private ManualResetEvent manualResetEvent;
private PoorMansSynchronizier poorMansSynchronizier;
public AutomationBackgroundWorker()
{
Thread.CurrentThread.Name = "Automation Background Worker";
poorMansSynchronizier = new PoorMansSynchronizier(thread =>
{
thread.Name = "Automation Thread";
thread.SetApartmentState(ApartmentState.STA);
});
manualResetEvent = new ManualResetEvent(false);
}
public void Begin()
{
poorMansSynchronizier.Invoke(() => Automation());
manualResetEvent.WaitOne();
}
public void Complete()
{
manualResetEvent.Set();
manualResetEvent.Close();
poorMansSynchronizier.Complete();
}
public void Automation()
{
AutomationMessenger.Send("Status", "Initializing", null);
// Initialize Automation Elements, etc..
Task.Delay(1000).Wait();
AutomationMessenger.Send("Status", "Initialized", null);
// Get user input
AutomationMessenger.Send("UserInput", "Please Enter Your Name", UserInputCallback);
// Wait for their response
}
private void UserInputCallback(string userInput)
{
poorMansSynchronizier.Invoke(() =>
{
// Do something with the response
if (string.IsNullOrWhiteSpace(userInput)) return;
AutomationMessenger.Send("Status", $"Thanks {userInput}", null);
Complete();
});
}
}
The key here is, that the poor man's synchronizer has its own Thread
, and its purpose is to execute each item on the queue.
I was able to do away with the background worker having to hold a reference to the old automationThread
in the original question code, and now any action I need to run on the STA automation thread, I just pass to the queue.
This has no effect on the original implementation of the non-user-facing automation code- As far as it knows, it's still running on an STA thread named Automation Thread, and it's as happy as it was before the user-facing requirements were implemented- No doom and gloom or crippling technical debt that only a giant refactor of the automation code could solve @Enigmativity.
Proper way to synchronize a property's value in a multi-threaded application
- Yes, the
lock (OptionsLock)
ensures that all threads will see the latest value of theOptions
, because memory barriers are inserted when entering and exiting thelock
. - Replacing the
lock
with methods of theInterlocked
or theVolatile
class would serve equally well the latest-value-visibility goal. Memory barriers are inserted by these methods as well. I think that using theVolatile
communicates better the intentions of the code:
public ContactOptions Options
{
get => Volatile.Read(ref _Options);
set => Volatile.Write(ref _Options, value);
}
- Omitting the barrier in either the
get
or theset
accessor puts you automatically in the big black forest of memory models, cache coherency protocols and CPU architectures. In order to know if it's safe to omit it, intricate knowledge of the targeted hardware/OS configuration is required. You will need either an expert's advice, or to become an expert yourself. If you prefer to stay in the realm of software development, don't omit the barrier!
Related Topics
How to Get the Value of Private Field Using Reflection
Removing Dynamically Created Controls in C#
Cannot Deserialize the Current JSON Array (E.G. [1,2,3]) into Type
"Requested Uri Is Invalid" During Upload with Ftpwebrequest
Caliburn.Micro Serialization Issue When Implementing Propertychangedbase
How to Draw Shapes in Winforms
How to Re-Write a SQL Query as a Parameterized Query
Entity Framework - Add Navigation Property Manually
Custom Path of the User.Config
Format Decimal for Percentage Values
Detect If PDF File Is Correct (Header PDF)
A Dictionary Object That Uses Ranges of Values for Keys
How to Export Datagridview Data Instantly to Excel on Button Click