Can't reproduce threading deadlock with MethodImplOptions.Synchronized - c#

I'm trying to reproduce some deadlock with only MethodImplOptions.Synchronized method notation:
using System;
using System.Threading;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.CompilerServices;
namespace Lab_01
{
class Program1
{
[MethodImpl(MethodImplOptions.Synchronized)]
static void Resource1(int starterIndex, bool startNext = true)
{
Console.WriteLine("Resource1 is used ({0})", starterIndex);
Thread.Sleep(1000);
if (startNext)
{
Resource2(starterIndex, false);
}
Console.WriteLine("Resource1 is free ({0})", starterIndex);
}
[MethodImpl(MethodImplOptions.Synchronized)]
static void Resource2(int starterIndex, bool startNext = true)
{
Console.WriteLine("Resource2 is used ({0})", starterIndex);
Thread.Sleep(1000);
if (startNext)
{
Resource1(starterIndex, false);
}
Console.WriteLine("Resource2 is free ({0})", starterIndex);
}
static void Main(string[] args)
{
Locker locker1 = new Locker();
Locker locker2 = new Locker();
new Thread(delegate()
{
Resource1(0);
}).Start();
new Thread(delegate()
{
Resource2(1);
}).Start();
}
}
}
What I expect is
1st thread is started and only the Resource1 method is locked, it waits for 1 sec
While 1st thread is sleeping (this 1 second) 2nd thread is started and it locks the 2nd resource (Resource2). It sleeps for 1 sec.
The thread, which ends the sleep first, say 1st thread, want to lock the 2nd resource, but it can't because it's already locked, and can't be freed, because the second thread is in the same situation (it wants to lock Recource1, but it's already locked). In one word, the regular deadlock situation.
But when I start it it doesn't lock itself and I'm getting this output:
C:\Users\ginz\C#\19-\Lab_01\Lab_01\bin\Debug>Lab_01.exe
Resource1 is used (0)
Resource2 is used (0)
Resource2 is free (0)
Resource1 is free (0)
Resource2 is used (1)
Resource1 is used (1)
Resource1 is free (1)
Resource2 is free (1)
So, the second thread is started only when the first thread has come to the end, but I think it should start much earlier. Why is this?
I know this behavior can be simply reproduced by using lock keyword, but in my case that's inappropriate way:
Object obj1 = new Object(), obj2 = new Object();
new Thread(new ThreadStart(delegate()
{
lock (obj1)
{
Thread.Sleep(1000);
lock (obj2)
{
Thread.Sleep(500);
}
}
})).Start();
new Thread(new ThreadStart(delegate()
{
lock (obj2)
{
Thread.Sleep(1000);
lock (obj1)
{
Thread.Sleep(500);
}
}
})).Start();
Could you please help me in this situation?
Thanks in advance,
Dmitry

Related

Is there any low level metric/logging of thread locks in .NET?

Over the years, I've not really come across this if it exists, so I'm putting this out there to understand if anyone knows of any low-level .NET functionality, maybe within reflection, that can capture when a thread has become locked? Some kind of logging perhaps?
private object _lockObject = new object();
void MyFunc()
{
lock(_lockObject) // <== How can I understand how many threads are waiting on this?
{
// Do work
}
}
Is it workable to put together some kind of lock handler and pass it a predicate such as...?
void DoLock(object lockObject, Action predicate)
{
push(threadid);
lock(lockObject)
{
pop(threadid);
predicate();
}
}
You can get some information via PerformanceCounter.
In order to do this, you will need to know the name of the process that you want to monitor.
The performance counter category name is ".NET CLR LocksAndThreads", and the counter names for that category are shown in the table on the page I linked above.
The monitoring is typically performed from a different process than the one being monitored, but for simplicity here is a sample console application that monitors itself:
using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApp1
{
class Program
{
static void Main()
{
var counter1 = new PerformanceCounter(".NET CLR LocksAndThreads", "Contention Rate / sec", "ConsoleApp1");
var counter2 = new PerformanceCounter(".NET CLR LocksAndThreads", "Total # of Contentions", "ConsoleApp1");
Task.Run(() => test());
Task.Run(() => test());
Task.Run(() => test());
Task.Run(() => test());
while (true)
{
Thread.Sleep(100);
Console.WriteLine($"Contention: {counter1.NextValue()}/sec, Total: {counter2.NextValue()}");
}
}
static object locker = new object();
static void test()
{
while (true)
{
lock (locker)
{
Thread.Sleep(50);
}
}
}
}
}

Out of memory exception while playing with Monitor.Wait and Monitor.Pulse

I was playing with the Monitor class in .NET so I arrived at a piece of code that seem to be working but when I loop it for a while it throws an OutOfMemoryException.
I am running this on a 64 bit windows 8 developer machine with 8 GB of RAM and I the process never takes up more than a 100 MB of space on the RAM.
This is my code:
using System;
using System.Threading;
public class Program
{
public static void Main()
{
while (true) {
object theLock = new Object();
Thread threadA = new Thread(() =>
{
Console.WriteLine("Thread A before lock");
lock (theLock)
{
Console.WriteLine("Thread A locking, about to Wait");
Monitor.Wait(theLock);
}
Console.WriteLine("Thread A after lock");
});
Thread threadB = new Thread(() =>
{
Console.WriteLine("Thread B before lock");
lock (theLock)
{
Console.WriteLine("Thread B lockint, about to Pulse");
Monitor.Pulse(theLock);
}
Console.WriteLine("Thread B before lock");
});
threadA.Start();
threadB.Start();
GC.Collect();
}
}
}
I read here that it might be a fragmentation problem and I added the GC.Collect() at the end. However I am not allocating big chunks of space.
Then I decided to measure how many iterations does the loop go through approximately before it throws the exception and added a counter:
using System;
using System.Threading;
public class Program
{
public static void Main()
{
int counter = 0;
while (true) {
Console.WriteLine(counter);
counter++;
object theLock = new Object();
Thread threadA = new Thread(() =>
{
Console.WriteLine("Thread A before lock");
lock (theLock)
{
Console.WriteLine("Thread A locking, about to Wait");
Monitor.Wait(theLock);
}
Console.WriteLine("Thread A after lock");
});
Thread threadB = new Thread(() =>
{
Console.WriteLine("Thread B before lock");
lock (theLock)
{
Console.WriteLine("Thread B lockint, about to Pulse");
Monitor.Pulse(theLock);
}
Console.WriteLine("Thread B before lock");
});
threadA.Start();
threadB.Start();
GC.Collect();
}
}
}
That seems to slow down the throwing of the exception a lot. I measured 36000 iterations.
For each pair of threads, if thread A manages to acquire the lock before thread B, you'll end up with both threads completing, and everything can be cleaned up.
If thread B manages to acquire the lock before thread A, thread B will complete (having pulsed the monitor) but then thread A will acquire the monitor and wait forever for something to pulse it. So at that point you'll have:
A Thread object
An OS thread
The object that the thread is waiting on
... all of which are tied up forever, basically.
Given that, I'm not surprised that you're seeing problems.
It's not clear what you're trying to achieve, but that explains the symptoms. Never assume that just because you call threadA.Start() before threadB.Start(), the first thread will actually reach a certain point in code before the second thread.

Locking is not working

This is my code:
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApplication4
{
class Writer {
public void Write(string xxx) { Console.Write(xxx); }
}
class Program
{
static Writer wrt;
static void Main(string[] args)
{
wrt = new Writer();
Thread trd = new Thread(new ThreadStart(delegate() {
lock (wrt)
{
Thread.Sleep(1000);
wrt.Write("1");
}
}));
trd.Start();
wrt.Write("0");
Console.ReadLine();
}
}
}
The excepted output is "10", but the output is "01". Why?
You need to lock in both places:
wrt = new Writer();
Thread trd = new Thread(new ThreadStart(delegate() {
lock (wrt)
{
Thread.Sleep(1000);
wrt.Write("1");
}
}));
trd.Start();
lock(wrt) // Lock here, too
{
wrt.Write("0");
}
Console.ReadLine();
Using a lock doesn't prevent that instance from being used other places, it just prevents that instance from being used to acquire another lock until your lock is done.
Instead of thinking of lock as "locking the object", think of it as your object is the one and only key for that lock - no other lock(yourObject) can "unlock" that block of code until the first one is done.
Note that this will still likely show "01" as output, as it's very unlikely that the thread will startup quickly enough to get the lock first, but that's not deterministic.
Why not use Tasks? It will ensure that the first thread is complete before continuing with the next thread.
class Program
{
static void Main(string[] args)
{
var writer = new Writer();
var task = Task.Factory.StartNew(() =>
{
writer.Write("1");
});
task.ContinueWith((data) =>
{
writer.Write("0");
});
Console.ReadKey();
}
}
public class Writer
{
public void Write(string message)
{
Console.Write(message);
}
}
The statement wrt.Write("0"); in the main thread is executed before the trd thread. The main thread starts the trd thread and keeps executing the statements those come under main thread thats why the Write statement under main thread is executing before trd thread.
The lock statement is inside trd thread and thus has nothing to do with wrt.Write under main thread. You can put lock on main thread as Reed Copsey suggested but you can not ensure which thread will get lock first. It could be main thread which gets the lock first.
You can ensure the trd thread finsishes execution prior to main thread by calling Thread.Join after starting thread trd, it will ensure main thread will wait until trd thread finishes the exectuion. This will ensure that you get 10 instead of 01.
static Writer wrt;
static void Main(string[] args)
{
wrt = new Writer();
Thread trd = new Thread(new ThreadStart(delegate() {
lock (wrt)
{
Thread.Sleep(1000);
wrt.Write("1");
}
}));
trd.Start();
trd.Join();
wrt.Write("0");
Console.ReadLine();
}

Monitor.Pulse(this) does not trigger Monitor.Wait(this);

I'm trying to get Monitor.Pulse(this) to trigger Monitor.Wait(this) in my code. I think my Wait statements are all running at some point with no Pulse. I have 5 different threads run by 5 different objects, each representing a queue with different priority. I'm trying to get each thread to run with a certain priority without using the thread priority attribute (i.e. normal, abovenormal, etc.). Anyways, point is that each thread only runs once and then it seems they are stuck at the Monitor.Wait(this) part in the thread that runs for each queue. Does anyone know why the Monitor.Pulse(this) doesn't trigger the Monitor.Wait(this) and continue the cycle. Each thread should be triggered one after the other by the Monitor.Wait(this) and the while loop that uses the Global variable GlobalCount. I think the problem must occur in my Beta method in the first class (Msg class) at the top where this triggering occurs. Or in my main method, although I'm less sure of that part having an issue.
What happens is it will execute a few lines and then start a new line but won't print anything else. The code is still running. I also tried removing the Monitor.Pulse and Monitor.Wait and it partially works, but every time the delta object's beta method runs its thread it is replaced by the alpha method. Does anyone know why this is and how I can get Pulse and Wait to work?
Here is my code (ignore some of the comments):
// StopJoin.cs
using System;
using System.Threading;
using System.Collections;
public class Msg
{
string message;
int priority;
public Msg(string ms, int pr)
{message = ms;
priority = pr;}
// This method that will be called when the thread is started
public void Beta()
{
while(true){
//Console.WriteLine("asdfasdfs");
Console.WriteLine(message+":"+GlobalClass.globalCount);
lock(this) // Enter synchronization block
{
while((priority - 1) != GlobalClass.globalCount){
//Console.WriteLine(GlobalClass.globalCount);
try
{
// Waits for the Monitor.Pulse in WriteToCell
//Console.WriteLine("beginning");
//Monitor.Wait(this);
//Console.WriteLine("end");
}
catch (SynchronizationLockException e)
{
Console.WriteLine(e);
}
catch (ThreadInterruptedException e)
{
Console.WriteLine(e);
}
if(GlobalClass.globalCount >= 5)
GlobalClass.globalCount = 0;
}
Console.WriteLine(message+".Beta is running in its own thread.");
for(int i = 0;i<priority;i++)
{
Console.WriteLine("sending message...");
}
if(GlobalClass.globalCount < 5)
GlobalClass.globalCount = GlobalClass.globalCount + 1;
//Monitor.Pulse(this); // Pulse tells Cell.WriteToCell that
//Console.WriteLine(GlobalClass.globalCount);
}
}
}
}
public class Alpha
{
Msg the_message = new Msg("Alpha",1);
public void doWork()
{the_message.Beta();}
};
public class Charlie
{
Msg the_message = new Msg("Charlie",2);
public void doWork()
{the_message.Beta();}
};
public class Delta
{
Msg the_message= new Msg("Alpha",3);
public void doWork()
{the_message.Beta();}
};
public class Echo
{
Msg the_message= new Msg("Echo",4);
public void doWork()
{the_message.Beta();}
};
public class Foxtrot
{
Msg the_message= new Msg("Foxtrot",5);
public void doWork()
{the_message.Beta();}
};
static class GlobalClass
{
private static int global_count = 0;
public static int globalCount
{
get{return global_count;}
set{global_count = value;}
}
}
public class Simple
{
public static int Main()
{
GlobalClass.globalCount = 2;
long s = 0;
long number = 100000000000000000;
Console.WriteLine("Thread Start/Stop/Join Sample");
Alpha oAlpha = new Alpha();
Charlie oCh = new Charlie();
Delta oDe = new Delta();
Echo oEc = new Echo();
Foxtrot oFo = new Foxtrot();
// Create the thread object, passing in the Alpha.Beta method
// via a ThreadStart delegate. This does not start the thread.
Thread oThread = new Thread(new ThreadStart(oAlpha.doWork));
Thread aThread = new Thread(new ThreadStart(oCh.doWork));
Thread bThread = new Thread(new ThreadStart(oDe.doWork));
Thread cThread = new Thread(new ThreadStart(oEc.doWork));
Thread dThread = new Thread(new ThreadStart(oFo.doWork));
// Start the thread
oThread.Start();
aThread.Start();
bThread.Start();
cThread.Start();
dThread.Start();
// Spin for a while waiting for the started thread to become
// alive:
while (!oThread.IsAlive);
while (!aThread.IsAlive);
while (!bThread.IsAlive);
while (!cThread.IsAlive);
while (!dThread.IsAlive);
// Put the Main thread to sleep for 1 millisecond to allow oThread
// to do some work:
Thread.Sleep(1);
// Wait until oThread finishes. Join also has overloads
// that take a millisecond interval or a TimeSpan object.
oThread.Join();
aThread.Join();
bThread.Join();
cThread.Join();
dThread.Join();
Console.WriteLine();
Console.WriteLine("Alpha.Beta has finished");
/*
try
{
Console.WriteLine("Try to restart the Alpha.Beta thread");
oThread.Start();
}
catch (ThreadStateException)
{
Console.Write("ThreadStateException trying to restart Alpha.Beta. ");
Console.WriteLine("Expected since aborted threads cannot be restarted.");
}
*/
while(s<number)
s++;
// Request that oThread be stopped
oThread.Abort();
aThread.Abort();
bThread.Abort();
cThread.Abort();
dThread.Abort();
return 0;
}
}
I can see a number of problems with your code, but there are two main ones that will be affecting you. I've assumed that your commented out Monitor calls shouldn't be commented (else the code makes no sense).
Firstly, you create a new instance of Msg under each thread. The Beta method locks on the current instance of Msg (in the commented Monitor.Wait(this)), and so each instance is essentially waiting on itself - which will be an infinite wait, because the only Monitor.Pulse is later in the same method, and will never be reached.
Because some of your Msg instances will be created with a higher value for priority, they will skip the while loop entirely and should continue to call Monitor.Pulse, but there will be nothing waiting on that pulse.
Later in your Main method, you have the following:
while (!oThread.IsAlive) ;
while (!aThread.IsAlive) ;
while (!bThread.IsAlive) ;
while (!cThread.IsAlive) ;
while (!dThread.IsAlive) ;
This is flawed. Because there's no guarantee of the execution order of your threads, it's entirely possible for the above code to deadlock. If your oThread isn't started immediately, but dThread is scheduled and runs to completion, you could easily see a case where dThread is completed and "dead" before the final line above is reached.
All in all, I'm not clear on what your code is trying to achieve, but as it stands I'd expect it to deadlock every time.

Alternating threads #2

Imagine a situation in which there are one king and n number of minions submitted to him. When the king says "One!", one of the minions says "Two!", but only one of them. That is, only the fastest minion speaks while the others must wait for another call of the king.
This is my try:
using System;
using System.Threading;
class Program {
static bool leaderGO = false;
void Leader() {
do {
lock(this) {
//Console.WriteLine("? {0}", leaderGO);
if (leaderGO) Monitor.Wait(this);
Console.WriteLine("> One!");
Thread.Sleep(200);
leaderGO = true;
Monitor.Pulse(this);
}
} while(true);
}
void Follower (char chant) {
do {
lock(this) {
//Console.WriteLine("! {0}", leaderGO);
if (!leaderGO) Monitor.Wait(this);
Console.WriteLine("{0} Two!", chant);
leaderGO = false;
Monitor.Pulse(this);
}
} while(true);
}
static void Main() {
Console.WriteLine("Go!\n");
Program m = new Program();
Thread king = new Thread(() => m.Leader());
Thread minion1 = new Thread(() => m.Follower('#'));
Thread minion2 = new Thread(() => m.Follower('$'));
king.Start();
minion1.Start();
minion2.Start();
Console.ReadKey();
king.Abort();
minion1.Abort();
minion2.Abort();
}
}
The expected output would be this (# and $ representing the two different minions):
> One!
# Two!
> One!
$ Two!
> One!
$ Two!
...
The order in which they'd appear doesn't matter, it'd be random. The problem, however, is that this code, when compiled, produces this instead:
> One!
# Two!
$ Two!
> One!
# Two!
> One!
$ Two!
# Two!
...
That is, more than one minion speaks at the same time. This would cause quite the tumult with even more minions, and a king shouldn't allow a meddling of this kind.
What would be a possible solution?
For future readers, here's the final, working code:
using System;
using System.Threading;
class Program {
static AutoResetEvent leader = new AutoResetEvent(false);
static AutoResetEvent follower = new AutoResetEvent(false);
void Leader() {
do {
Console.WriteLine(" One!");
Thread.Sleep(300);
follower.Set(); // Leader allows a follower speak
leader.WaitOne(); // Leader waits for the follower to finish speaking
} while(true);
}
void Follower (char emblem) {
do {
follower.WaitOne(); // Follower waits for the leader to allow speaking
Console.WriteLine("{0} Two!", emblem);
leader.Set(); // Follower finishes speaking
} while(true);
}
static void Main() {
Console.WriteLine("Go!\n");
Program m = new Program();
Thread king = new Thread(() => m.Leader());
Thread minion1 = new Thread(() => m.Follower('#'));
Thread minion2 = new Thread(() => m.Follower('$'));
Thread minion3 = new Thread(() => m.Follower('&'));
king.Start();
minion1.Start();
minion2.Start();
minion3.Start();
Console.ReadKey();
king.Abort();
minion1.Abort();
minion2.Abort();
minion3.Abort();
}
}
Try using an AutoResetEvent instead of a lock/monitor. It allows you to create a "gate" that only one thread can get through at a time.
Your Follower() threads would call event.WaitOne() (optionally with a timeout). Your Leader() function would call event.Set(), which will release one of the waiting threads.
An AutoResetEvent (as opposed to other types of wait handles) will automatically "close the gate" once of the waiting threads is through.
http://msdn.microsoft.com/en-us/library/system.threading.autoresetevent.aspx
You aren't locking the followers down. So both threads are seeing leaderGo are true, and respond. Have the thread lock itself down before writing out, and that should fix it.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
namespace Threading
{
class Program
{
static bool leaderGO = false;
static bool followerGo = false;
void Leader()
{
do
{
lock (this)
{
//Console.WriteLine("? {0}", leaderGO);
if (leaderGO) Monitor.Wait(this);
Console.WriteLine("> One!");
Thread.Sleep(200);
leaderGO = true;
followerGo = true;
Monitor.Pulse(this);
}
} while (true);
}
void Follower(char chant)
{
do
{
lock (this)
{
//Console.WriteLine("! {0}", leaderGO);
if (!leaderGO) Monitor.Wait(this);
if(followerGo)
{
followerGo = false;
Console.WriteLine("{0} Two!", chant);
leaderGO = false;
}
Monitor.Pulse(this);
}
} while (true);
}
static void Main()
{
Console.WriteLine("Go!\n");
Program m = new Program();
Thread king = new Thread(() => m.Leader());
Thread minion1 = new Thread(() => m.Follower('#'));
Thread minion2 = new Thread(() => m.Follower('$'));
king.Start();
minion1.Start();
minion2.Start();
Console.ReadKey();
king.Abort();
minion1.Abort();
minion2.Abort();
}
}
}
What you're experiencing is a race condition. You have two separate threads operating on an unlocked resource (leaderGo), which controls their access to the critical section (printing out "Two!").
Placing a mutex lock (as recommended by manman) on leaderGo before printing out "Two!" is a start. You will also need to check to ensure that the value of leaderGo is still true before printing it, as both threads will eventually acquire the lock, but only one of them will acquire the lock while leaderGo is true.
Something like:
lock(leaderGo)
{
if (leaderGo)
Console.WriteLine("{0} Two!", chant);
leaderGo = false;
}
This will ensure only one follower is capable of responding (since it requires the lock). It will not guarantee which thread obtains the lock, the frequency at which specific threads obtain the lock, or anything like that. However, in each pass every thread will obtain the lock -- all that matters is who was first.
A few tips:
NEVER use lock(this). By locking the object from the inside, anything that uses your object as a locking focus will interfere with your own code's ability to synchronize.
NEVER use Thread.Abort(). It is evil; it kills your running threads by injecting an exception, which is unpredictable and thus difficult or impossible to catch and handle gracefully. Instead, try passing an instance of a class with a boolean property IsCancelled, and use !IsCancelled as the condition under which you keep looping.
The actual problem with your code is that your combination of Monitor and locks is causing the lock to be released from within the critical section by the thread that acquires the lock, if that thread thinks someone else must go first. You have three threads, each of which can acquire, then release and wait, before reacquiring the lock and proceeding as if the condition under which it waited was now false.
One possible scenario:
Follower 1 enters the critical section (lock() block) of Follower.
Follower 2 approaches the critical section of Follower and is told to wait.
King approaches the critical section of Leader and is told to wait.
Follower 1 sees that leaderGO is false and waits, releasing the lock on the critical section.
King, despite being second in line, "races" into the critical section ahead of Follower 2.
King continues (leaderGo is false so King never Wait()s), calls "One!" and sets the flag before releasing the lock at the end of the critical section.
Follower 2 now "races" into the critical section ahead of Follower 1, sees the flag is set, and continues, calling "Two!" and exiting the critical section.
Follower 1 now gets a turn, reacquiring the lock in the middle of its critical section. It no longer cares that leaderGo is false; it's past that check already. So, it continues, also calls "Two!", sets the flag (to the value it had already been) and exits.
There are many possible ways that these threads could "race" based on the way you have it set up.
Here's something that may work a little better; it's called double-checked locking, and while it isn't foolproof it's much better than what you have:
private static readonly object syncObj = new object();
void Leader() {
do {
if(leaderGo)
{
Thread.Sleep(200);
continue;
}
lock(syncObj) {
//the "double-check"; here it's not necessary because there's
//only one King to set leaderGo to true,
//but it doesn't hurt anything.
if(leaderGo) continue;
//we won't get here unless we have control of
//the critical section AND must do something.
Console.WriteLine("> One!");
Thread.Sleep(200);
leaderGO = true;
}
} while(true);
}
void Follower (char chant) {
do {
if(!leaderGo)
{
Thread.Yield();
continue;
}
lock(syncObj) {
//this double-check is critical;
//if we were waiting on the other follower to release
//the lock, they have already shouted out and we must not do so.
if (!leaderGO) continue;
//we only get here if we have
//control of the lock and should shout out
Console.WriteLine("{0} Two!", chant);
leaderGO = false;
}
} while(true);
}
EDIT: As mentioned in the comments, this model doesn't rely on luck, but it isn't foolproof because .NET, for performance, can allow several copies of leaderGO to exist in the caches of various threads, and synchronize them behind the scenes. If .NET isn't johnny-on-the-spot with that synchronization, the double-check performed by one thread may see the old, "stale" state of the flag and incorrectly move on when it should instead get out.
You can fix this one of two simple ways:
Put a MemoryBarrier just after any update of leaderGO, and just before any read of leaderGO. Memory barriers, or "memory fences" as they can be called in other languages, basically blocks each running thread at the memory barrier, until all threads are at a memory barrier (or blocked in other ways), ensuring that all instructions occurring before the memory barrier have been executed before any instructions after it are run.
Declare leaderGO as volatile. A volatile variable cannot be optimized by .NET; it is guaranteed to be in exactly one location in memory that is accessible, however inefficiently, by any thread that would run that code. Therefore any update to its value is immediately seen by any other thread.

Categories