How can i lock a part of method in c# from another threads?
I mean if one of threads was here, then exit...
For example:
if(threads[0].WasHere)
{
return;
}
an effective way is with an interlocked exchange; by setting some token field to a non-default value during the work, the other threads can check this and exit. For example:
private int hazWorker; // = 0 - put this at the scope you want to protect
then:
// means: atomically set hazWorker to 1, but only if the old value was 0, and
// tell me what the old value was (and compare that result to 0)
if(Interlocked.CompareExchange(ref hazWorker, 1, 0) != 0) {
return; // someone else has the conch
}
try {
// your work here
} finally {
Interlocked.Exchange(ref hazWorker, 0); // set it back to default
}
You can use Monitor.TryEnter for this purpose.
if(!Monitor.TryEnter(someLock))
{
return;
}
try
{
//Critical region
}
finally
{
Monitor.Exit(someLock);
}
Or more reliable way to fight with Rude Thread aborts (suggested by marc in comments)
bool lockTaken = false;
try
{
Monitor.TryEnter(someLock, ref lockTaken);
if (lockTaken)
{
//Critical region
}
}
finally
{
if(lockTaken) Monitor.Exit(someLock);
}
Note that this doesn't checks for threads[0] still working, rather it checks whether any other thread is in Critical region. If so, it exits the method.
You can use a bool value - assign it "false" on default, and then the first of the threads sets it to "true". And then the piece of code could look like this:
if (!alreadyExecuted)
{
// ...
alreadyExecuted = true;
}
I would also put the code in a lock to make sure only one thread executes it at time (to deal with any possible race conditions), like below.
The lockVariable is a locker variable and it can be of any reference type, ex. object lockVariable = new object();
lock (lockVariable)
{
if (!alreadyExecuted)
{
// ...
alreadyExecuted = true;
}
}
Related
I couldn't find any information on whether the C# compiler or JIT will remove a lock statement with no code inside. Will this always generate and execute the Monitor.Enter and Monitor.Exit calls?
lock(lockObj) { }
A (drastically simplified) version of what I'm trying to do (yes I know calling a callback in a lock is bad):
public class ExecutionSource
{
private List<Action<object>> _callbacks = new List<Action<object>>();
private object _value;
public void AddListener(Action<object> listener)
{
object temp = _value;
if (temp != null)
{
listener(temp);
return;
}
lock (_callbacks)
{
temp = _value;
if (temp != null)
{
listener(temp);
}
else
{
_callbacks.Add(listener);
}
}
}
public void Execute(object value)
{
if (value == null) throw new InvalidOperationException("value must be non-null");
if (Interlocked.CompareExchange(ref _value, value, null) != null)
{
throw new InvalidOperationException("Can only execute once.");
}
lock (_callbacks) { } // Wait for a listener that is currently being added on another thread. No need to lock the entire loop.
foreach (var callback in _callbacks)
{
callback(value);
}
_callbacks.Clear();
}
}
No, they do not. The CLI cannot assume there is no other thread already locking over the object.
The object header or sync block table will still get marked with the Thread ID and a non zero recursion count on Monitor.Enter/Exit, if any other thread (or your current code) tries to lock over the object with a non zero thread id, it will go into a spin wait or promote to a kernel based event if needed.
For what it's worth, since you have no care for reordering, and depending on what your use cases are, there are likely other synchronization primitives that might be a better fit for your particular use case. Like a reset event etc.
As per sharplib we can see that compiler do not remove empty lock block. Moreoever, I can't imagine how we can optimize it out in compile-time in real multithreading environment and be sure that we do not broke anything.
I want to run a cleanup task that might run for several seconds. Multiple threads could call this task but I want to run this task only once. All other invokations should just skip.
The following is my current implementation but I cannot imagine there is not a better solution in the .net framework resulting in less lines of code.
object taskLock;
bool isRunning;
void Task()
{
if (isRunning) return;
try
{
lock (taskLock)
{
if (isRunning) return;
isRunning = true;
}
// Perform the magic
}
finally
{
isRunning = false;
}
}
Yes, there is a better solution. You can use Interlocked.CompareExchange, the code becomes simpler and lock-free:
class Worker
{
private volatile int isRunning = 0;
public void DoWork()
{
if (isRunning == 0 && Interlocked.CompareExchange(ref isRunning, 1, 0) == 0)
{
try
{
DoTheMagic();
}
finally
{
isRunning = 0;
}
}
}
private void DoTheMagic()
{
// do something interesting
}
}
In this case Interlocked.CompareExchange does the following as an atomic operation (pseudo-code):
wasRunning = isRunning;
if isRunning = 0 then
isRunning = 1
end if
return wasRunning
From the MSDN documentation:
public static int CompareExchange(
ref int location1,
int value,
int comparand
)
If comparand and the value in location1 are equal, then value is
stored in location1. Otherwise, no operation is performed. The compare
and exchange operations are performed as an atomic operation. The
return value of CompareExchange is the original value in location1,
whether or not the exchange takes place
I have a method that can be called from many threads, but I just want the 1st thread to do some logic inside the method. So, I'm planning to use a boolean variable. The first thread that comes in, will set the boolean variable to false (to prevent further threads to come inside), and execute the method logic.
Subsequent threads that come to this method, will check the boolean variable. Because it was set to false by the 1st thread, they will skip the method logic.
In code, something like this:
private void myMethod()
{
if (firsTime) //set to true in the constructor
{
firstTime = false; //To prevent other thread to come inside here.
//method logic
}
}
I want to use lock to perform this, but not sure where to put it.
If I lock inside the "if" to change firstTime to false, its possible 2 or more threads already come inside the if (don't want this).
If I lock outside the "if" to change firstTime to false, how can the 1st thread go inside the if to execute the method logic, if firstTime its already set to false??
My question is : how to do the lock to have the desired functionality? (1st thread that comes set the boolean and execute method logic).
I cannot lock over all the method logic, since it will be a very long time consuming operations.
You can use Interlocked.Exchange to solve this problem. It will set the value of the given variable to the specified value and return the value that used to be in the variable, and it will do it all atomically. Doing this will ensure that only one thread will ever run the code in the if:
private static int isFirst = 1;
public static void Foo()
{
if (Interlocked.Exchange(ref isFirst, 0) == 1)
{
//DoStuff
}
}
Note that Interlocked.Exchange has no overload that takes a bool, which is why you're forced to use an int (or some other type) instead, using 1 for true and 0 for false.
If you want a solution using lock, rather than Interlocked, you can do it through the use of an additional local bool value:
private static bool isFirst = true;
private static object key = new object();
public static void Foo()
{
bool amFirst;
lock (key)
{
amFirst = isFirst;
isFirst = false;
}
if (amFirst)
{
//DoStuff
}
}
I have a class that talks to an external .exe. The class has a bunch of similar methods; they call a function of the .exe, wait for response, and then return true or false.
The response comes in the form of events that change the values of fields of this class.
Simplified code:
class Manager
{
private static bool connected = false;
public static bool Connect()
{
runtime.Connect();
int secondsWaited = 0;
while (!connected)
{
Thread.Sleep(1000);
if (secondsWaited++ == 10)
{
return false;
}
}
return true;
}
}
The other methods use the same call-wait-loop-return structure.
My goal is to make a single method to do this waiting for me, like so:
private static bool WaitReferenceEqualsValue<T>(ref T reference, T value)
{
int secondsWaited = 0;
while (!reference.Equals(value))
{
Thread.Sleep(1000);
if (secondsWaited++ == 10)
{
return false;
}
}
return true;
}
Then each method would do:
runtime.DoSomething();
return WaitReferenceEqualsValue<someType>(ref someField, someSuccessfulValue);
However, when I replace the wait-loop with this method call, the field "connected", even though passed in as a reference, always stays the same.
Any idea what's going on here, and how to get the desired functionality?
Thanks in advance.
EDIT:
public static bool Connect()
{
...
runtime.Connect();
// this code works
/*int secondsWaited = 0;
while (connected != true)
{
Thread.Sleep(1000);
if (secondsWaited++ == 10)
{
return false;
}
}*/
// this somehow blocks OnConnect from firing, so connected never gets set to true
lock (typeof(SkypeKitManager))
{
WaitReferenceEqualsValue<bool>(ref connected, true);
}
...
}
OnConnect:
private static void OnConnect(object sender, Events.OnConnectArgs e)
{
if (e != null && e.success)
{
lock (typeof(Manager))
{
connected = true;
}
}
}
You're not doing any synchronization on that field although you access it from multiple threads and one of them is writing. This is a race (no exception! this is a race even if it looks safe. It isn't safe.).
Probably the JIT enregistered it which is a common optimization. It just never gets read from memory, always from a register. Add synchronization (for example a lock, or Interlocked or Volatile methods).
Your usage of ref is correct.
The problem with your code is essentially compiler optimization. Fo optimization purpose compilers (or jits) necessarily take a pretty much single threaded view. The compiler/jit will then notice that you don't touch reference in your code at all, therefore it can move the comparison outside the loop. It is free to do so, since you basically create a race condition (no synchronization/atomic accesses).
Fixing it could either involve using synchronization mechanisms or add the volatile specifier to reference, thus telling the compiler/jit, that the variable can be changed from outside the method.
I need to implement simple function that is called from multiple threads. The logic of the function is simple - think of horse races - only the first horse can get golden medal once we have a winner the race is over.
class ConditionalOrderGroup
{
private volatile bool _locked = false;
private List<ConditionalOrder> _ConditionalOrderList = null;
public bool LockGroup(ConditionalOrder initiator)
{
// this is finishline - we need to let only the first one proceed
if (_locked)
return false;
else
{
_locked = true;
}
// this is what winner gets
foreach (ConditionalOrder order in _ConditionalOrderList)
{
\\ cancel other orders
}
return true;
}
}
I am not happy with
if (_locked)
return false;
else
{
_locked = true;
}
What if two orders can pass if check and proceed to else. How to rewrite this code
without using lock statement?
UPDATE
I mean my goal is not use any blocking method like lock statement.
You need a separate, private object and use the built-in locking:
private object padLock = new object(); // 1-to-1 with _ConditionalOrderList
if (Monitor.TryEnter(padLock))
{
try
{
// cancel other orders
return true;
}
finally
{
Monitor.Exit(padLock);
}
}
else
{
return false;
}
Use Interlocked class to change values of the variable in a thread safe way.
Expanding on what decyclone said about interlocked, this is exactly how you would do it:
const int LOCKED = 1;
const int UNLOCKED = 0;
volatile int lockState = UNLOCKED;
public bool Foo()
{
try
{
//locking
//compare exchange returns the value that was in lockState before the compareExchange operation, so from that you can determine if you grabbed the lock or not
//if it was locked before, then you know the lock is not yours
if (Interlocked.CompareExchange(ref lockState, UNLOCKED, LOCKED) == LOCKED)
return false;
//lock is yours, do whatever stuff you like here, including throw exceptions
}
finally
{
//unlocking
//because this is in finally this lock will be released even if something goes wrong with your code
Interlocked.Exchange(ref lockstate, UNLOCKED);
}
}