I am just reading a great tutorial about threads and have a problem with locks. I need some tip/advice that will point me in right direction. I'd like to understand why the output isn't ordered as i expect. The code shows my simple example.
class Program {
class A {
public object obj = new object();
public int i;
}
class B {
public object obj = new object();
public int j;
}
static void Main() {
Console.Write("Thread1: ");
A a = new A();
for (a.i = 0; a.i < 9; a.i++) {
lock (a) {
new Thread(() => { Console.Write(a.i); }).Start();
}
}
Thread.Sleep(500);
Console.Write("\nThread2: ");
B b = new B();
for (b.j = 0; b.j < 9; b.j++) {
new Thread(() => { lock (b) { Console.Write(b.j); } }).Start();
}
Console.ReadLine();
}
}
Example output:
Thread1: 222456799
Thread2: 233357889
Link to the tutorial:
http://www.albahari.com/threading/
You are only locking while you create the thread, or (in the second case), access the value. Locks must be used by all threads, otherwise they do nothing. It is the act of trying to acquire the lock that blocks. Even if you did lock in both threads, that wouldn't help you marry each thread to the value of a.i (etc) at a particular point in time (that no longer exists).
Equally, threads work at their own pace; you cannot guarantee order unless you have a single worker and queue; or you implement your own re-ordering.
it will run at its own pace, and since you are capturing the variable a, it is entirely likely that the field a.i has changed by the time the thread gets as far as Console.Write. Instead, you should capture the value, by making a copy:
A a = new A();
for (a.i = 0; a.i < 9; a.i++) {
var tmp = a.i;
new Thread(() => { Console.Write(tmp); }).Start();
}
(or probably remove a completely)
for (int i = 0; i < 9; i++) {
var tmp = i;
new Thread(() => { Console.Write(tmp); }).Start();
}
there are several issues here:
First, you are locking on a when you create a thread, so the thread is created, but your original main thread then releases the lock and keeps on trucking in the loop, while the created threads run concurrently.
You want to move the first lock into the thread that uses A to the Thread delegate like this:
for(a.i=0;a.i<9;a.i++)
{
int id=a.i;
new Thread(()=>{ lock(a){Console.Out.WriteLine("Thread{0} sees{1}",id,a.i)};}).Start(); // lots of smileys here :)
}
If you look closely, you will notice that the threads are not locked the same way for A and B, which tells you that threads live their own lives and Thread creation != Thread life.
Even with locking your thread runners, you can and will end-up in situations where thread 1 runs AFTER thread 2... but they will never run at the same time thanks to your lock.
You also reference a shared member in all your threads: a.i. This member is initialized in the main thread which doesn't lock anything so your behaviour is not predictable. This is why I added the captured variable i that grabs the value of a.i when the thread is created, and is used in the thread delegate in a safe way.
Also, always lock on a non-public instance. if you lock on A, make sure no-one sees A and gets the opportunity to lock on it.
Because the lock is always held by the main thread, as you are starting threads after acquiring lock and once you acquire there is no contention. Now the threads are free to run however they want, the threads which started by main thread aren't synchronized by any lock. Something which comes close to your expections is following (only order) count again depends on how fast and how many cores you've got. Observe b.j++ is now inside a lock.
for (b.j = 0; b.j < 9; )
{
new Thread(() => { lock (b) { Console.Write(b.j); b.j++; } }).Start();
}
Basic idea behind locking or critical section is to only allow one thing to happen, not the order, in the above modification I've locked the increment operation, that gaurantees that before next thread starts running code under lock, current thread has to finish running all the code under its acquired lock, before it releases the lock.
Related
I began to study lock and immediately a question arose.
It docs.microsoft says here:
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.
I made a simple example proving that another thread with a method without the lock keyword can easily change the data of an instance while that instance is occupied by a method using the lock from the first thread. It is worth removing the comment from the blocking and the work is done as expected. I thought that a lock would block access to an instance from other threads, even if they don't use a lock on that instance in their methods.
Questions:
Do I understand correctly that locking an instance on one thread allows data from another thread to be modified on that instance, unless that other thread also uses that instance's lock? If so, what then does such a blocking generally give and why is it done this way?
What does this mean in simpler terms? While a lock is held, the thread that holds the lock can again acquire and release the lock.
So code formatting works well.
using System;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApp1
{
class A
{
public int a;
}
class Program
{
static void Main(string[] args)
{
A myA = new A();
void MyMethod1()
{
lock (myA)
{
for (int i = 0; i < 10; i++)
{
Thread.Sleep(500);
myA.a += 1;
Console.WriteLine($"Work MyMethod1 a = {myA.a}");
}
}
}
void MyMethod2()
{
//lock (myA)
{
for (int i = 0; i < 10; i++)
{
Thread.Sleep(500);
myA.a += 100;
Console.WriteLine($"Work MyMethod2 a = {myA.a}");
}
}
}
Task t1 = Task.Run(MyMethod1);
Thread.Sleep(100);
Task t2 = Task.Run(MyMethod2);
Task.WaitAll(t1, t2);
}
}
}
locks are cooperative, it relies on all parties that can change the data to cooperate and take the lock before attempting to change the data. Note that the lock does not care what you are changing inside the lock. It is fairly common to use a surrogate lock object when protecting some data structure. I.e.
private object myLockObject = new object();
private int a;
private int b;
public void TransferMonety(int amount){
lock(myLockObject){
if(a > amount){
a-=amount;
b+=amount;
}
}
}
Because of this locks are very flexible, you can protect any kind of operation, but you need to write your code correctly.
Because of this it is important to be careful when using locks. Locks should preferably be private to avoid any unrelated code from taking the lock. The code inside the lock should be fairly short, and should not call any code outside the class. This is done to avoid deadlocks, if arbitrary code is run it may do things like taking other locks or waiting for events.
While locks are very useful, there are also other synchronization primitives that can be used depending on your use case.
What does this mean in simpler terms? "While a lock is held, the thread that holds the lock can again acquire and release the lock."
It means that you can do this:
lock (locker)
{
lock (locker)
{
lock (locker)
{
// Do something while holding the lock
}
}
}
You can acquire the lock many times, and then release it an equal number of times. This is called reentrancy. The lock statement is reentrant, because the underlying Monitor class is reentrant by design. Other synchronization primitives, like the SemaphoreSlim, are not reentrant.
This question already has answers here:
C# "lock" keyword: Why is an object necessary for the syntax?
(3 answers)
Closed 4 years ago.
I do not speak English and I use translator.
I'm wondering when I'm studying thread synchronization.
class MainApp
{
static public int count = 0;
static private object tLock = new object();
static void plus()
{
for (int i = 0; i < 100; i++)
{
lock (tLock)
{
count++;
Console.WriteLine("plus " + count);
Thread.Sleep(1);
}
}
}
static void minus()
{
for (int i = 0; i < 100; i++)
{
lock (tLock)
{
count--;
Console.WriteLine("minus " + count);
Thread.Sleep(1);
}
}
}
static void Main()
{
Thread t1 = new Thread(new ThreadStart(plus));
Thread t2 = new Thread(new ThreadStart(minus));
t1.Start();
t2.Start();
}
}
Simple thread studying.
static private object tLock = new object();
lock (tLock) << argument value, why object argument??
Why have an object argument on lock?
Well, because it's convenient.
First of all, it's obvious in your code example that you need some shared state between the calls to lock, to declare that two different sections of code are mutually exclusive. If the syntax was just lock { } without a parameter, like this:
public void DoSomestuff()
{
lock
{
// Section A
}
}
public void DoOtherStuff()
{
lock
{
// Section B
}
}
Then either all locks would be mutually exclusive, or would impact only their individual portion of code (so two threads could execute section A and B concurrently, but only one thread at a time could execute A). This would greatly reduce the usefulness of the keyword.
Now that we established that we need a shared state, what this state should be? We could have used a string:
lock ("My Section")
{
// Section A
}
It would work but has a few drawbacks:
You expose yourself to potential collisions between the name of different sections in different libraries
It means that the runtime has to keep a kind of table to associate the string to a lock. Nothing too difficult, but that's some overhead
Instead, the .NET authors went for using an object argument. This solves problem 1/, as you know that another library won't have a reference to your object unless you willingly give it. But this also solves problem 2/, because this allows the runtime to store the lock in the actual object header. That's a pretty neat optimization.
Consider the following (without lock):
for (int i = 0; i < 1000; i++)
{
count++;
Console.WriteLine("plus " + count);
Thread.Sleep(1);
}
If two threads run simultaneously:
First thread adds one to count which is now 1.
Now second thread takes over and adds one to count which is now 2.
Second thread continues to print plus 2 and loops and again adds one to count which is now 3.
Now the first thread takes over and prints plus 3 which was not intended since count was 1 when WriteLine was to be called.
When adding a locking mechanism (lock) the developer makes sure that a part of the code is atomic, i.e. is run in sequence without interruption.
for (int i = 0; i < 1000; i++)
{
lock (tLock)
{
count++;
Console.WriteLine("plus " + count);
Thread.Sleep(1);
}
}
If you follow the same pattern here:
First thread adds one to count which is now 1.
Now second thread tries to take over but has to wait until the lock is released by the first thread.
First thread prints plus 1 and releases the lock.
Now second thread can take over and add one to count which is now 2.
First thread tries to take over but has to wait until the second thread releases the lock.
Second thread prints plus 2 and releases the lock.
As you can see the increment and WriteLine are now synchronized operations.
Edit
After you changed the question:
The lock keyword requires an object of reference type. It doesn't have to be an object. It can also be a class, interface, delegate, dynamic or string.
public static string a = string.Empty;
public static void Main()
{
lock(a)
{
Console.WriteLine("Hello World");
}
}
See the documentation for more information.
I have three threads and some part of the code can run in parallel, some parts are locked(only one thread at the time). However one lock needs to only let them in in order. Since this is a loop it gets more complex. How do I make this behavior?
If i had a print statement I would like to receive the following output:
1,2,3,1,2,3,1,2,3.... currently I receive 2,3,1,3,1,3,2,1,2 A.K.A. random order.
The code which is executed in three threads in parallel:
while (true){
lock (fetchLock){
if(done){
break;
}
//Do stuff one at the time
}
//Do stuff in parralell
lock (displayLock){
//Do stuff one at the time but need's to be in order.
}
}
You could use a combination of Barrier and AutoResetEvent to achieve this.
Firstly, you use Barrier.SignalAndWait() to ensure that all the threads reach a common point before proceeding. This common point is the point at which you want the threads to execute some code in order.
Then you use numberOfThreads-1 AutoResetEvents to synchronise the threads. The first thread doesn't need to wait for any other thread, but after it has finished it should signal the event that the next thread is waiting on.
The middle thread (or threads if more than 3 threads total) needs to wait for the previous thread to signal the event that tells it to proceed. After it has finished, the middle thread should signal the event that the next thread is waiting on.
The last thread needs to wait for the previous thread to signal the event that tells it to proceed. Since it is the last thread, it does not need to signal an event to tell the next thread to proceed.
Finally, you resync the threads with another call to Barrier.SignalAndWait().
This is easiest to show via a sample console app. If you run it, you'll see that the work that should be done by the threads in order (prefixed with the letter "B" in the output) is indeed always in order, while the other work (prefixed with the letter "A") is executed in a random order.
using System;
using System.Threading;
using System.Threading.Tasks;
namespace Demo
{
public static class Program
{
public static void Main()
{
using (Barrier barrier = new Barrier(3))
using (AutoResetEvent t2 = new AutoResetEvent(false))
using (AutoResetEvent t3 = new AutoResetEvent(false))
{
Parallel.Invoke
(
() => worker(1, barrier, null, t2),
() => worker(2, barrier, t2, t3),
() => worker(3, barrier, t3, null)
);
}
}
private static void worker(int threadId, Barrier barrier, AutoResetEvent thisThreadEvent, AutoResetEvent nextThreadEvent)
{
Random rng = new Random(threadId);
for (int i = 0; i < 1000; ++i)
{
doSomething(threadId, rng); // We don't care what order threads execute this code.
barrier.SignalAndWait(); // Wait for all threads to reach this point.
if (thisThreadEvent != null) // If this thread is supposed to wait for a signal
thisThreadEvent.WaitOne(); // before proceeding, then wait for it.
doWorkThatMustBeDoneInThreadOrder(threadId);
if (nextThreadEvent != null) // If this thread is supposed to raise a signal to indicate
nextThreadEvent.Set(); // that the next thread should proceed, then raise it.
barrier.SignalAndWait(); // Wait for all threads to reach this point.
}
}
private static void doWorkThatMustBeDoneInThreadOrder(int threadId)
{
Console.WriteLine(" B" + threadId);
Thread.Sleep(200); // Simulate work.
}
private static void doSomething(int threadId, Random rng)
{
for (int i = 0; i < 5; ++i)
{
Thread.Sleep(rng.Next(50)); // Simulate indeterminate amount of work.
Console.WriteLine("A" + threadId);
}
}
}
}
I'm trying to use Interlocked.Exchange to create a thread safe lock for some object initialize functions. Consider the below code. I want to be sure that the if is doing the same as when the while is substituted. The reason I ask is if the code is run over and over there are times when you get an exit message before the set message. I just would like to confirm that this is just a gui thing since the state on exit always seems to be correct.
class Program
{
private static void Main(string[] args)
{
Thread thread1 = new Thread(new ThreadStart(() => InterlockedCheck("1")));
Thread thread2 = new Thread(new ThreadStart(() => InterlockedCheck("2")));
Thread thread3 = new Thread(new ThreadStart(() => InterlockedCheck("3")));
Thread thread4 = new Thread(new ThreadStart(() => InterlockedCheck("4")));
thread4.Start();
thread1.Start();
thread2.Start();
thread3.Start();
Console.ReadKey();
}
const int NOTCALLED = 0;
const int CALLED = 1;
static int _state = NOTCALLED;
//...
static void InterlockedCheck(string thread)
{
Console.WriteLine("Enter thread [{0}], state [{1}]", thread, _state);
//while (Interlocked.Exchange(ref _state, CALLED) == NOTCALLED)
if (Interlocked.Exchange(ref _state, CALLED) == NOTCALLED)
{
Console.WriteLine("Setting state on T[{0}], state[{1}]", thread, _state);
}
Console.WriteLine("Exit from thread [{0}] state[{1}]", thread, _state);
}
}
I wouldn't call that a lock since it can be used only once, but you are correct if you assume that the statements inside the if scope would be executed exactly once even if InterlockedCheck is called from multiple threads concurrently.
That's because you're starting with NOTCALLED and only setting CALLED using the atomic Interlocked.Exchange. Only the first call would get back NOTCALLED in return while all subsequent calls would get back CALLED.
A better (and simpler) solution would be to use .Net's Lazy class which is perfect for initialization:
static Lazy<ExpensiveInstance> _lazy = new Lazy<ExpensiveInstance>(Initialization, LazyThreadSafetyMode.ExecutionAndPublication);
You can retrieve the result with _lazy.Value and query whether it was created with _lazy.IsValueCreated. The Initialization wouldn't run until it needs to and not more than once.
I don't see why you are using Interlocked here instead of the much more readable and easily-understood lock statement. Personally, I would advise the latter.
Either way, the reason you are seeing one or more "exit" messages before a "set" message is due to thread scheduling. Even though the first thread to hit the Interlocked will always perform the "set" operation, that thread may be pre-empted before it gets a chance to do the operation, allowing some other thread to emit its "exit" message first.
Note that depending on your exact needs here, while using an if is the same as using a while loop, it's probable that neither accomplish what you want. I.e. the first thread to hit the if is going to set the value to the CALLED value, and so any other thread will just keep on going. If you're really trying to initialize something here, you probably want the other threads to wait for the thread that is actually executing the initialization code, so that all threads can proceed knowing the initialized state is valid.
I do think one way or the other it would be a good idea (i.e. less confusing to the user, and more importantly if the real code is more complicated than what you've shown, is more likely to produce correct results) if you synchronize the entire method.
Using Interlocked to accomplish that is much more complicated than the code you have now. It would involve a loop and at least one additional state value. But with a lock statement, it's simple and easy to read. It would look more like this:
const int NOTCALLED = 0;
const int CALLED = 1;
static int _state = NOTCALLED;
static readonly object _lock = new object();
//...
static void InterlockedCheck(string thread)
{
lock (_lock)
{
Console.WriteLine("Enter thread [{0}], state [{1}]", thread, _state);
if (_state == NOTCALLED)
{
Console.WriteLine("Setting state on T[{0}], state[{1}]", thread, _state);
_state = CALLED;
}
Console.WriteLine("Exit from thread [{0}] state[{1}]", thread, _state);
}
}
That way, the first thread to acquire the lock gets to execute all of its code before any other thread does, and in particular it ensures that the "set" operation in that first thread happens before the "exit" operation in any other thread.
This is from MSDN:
The lock keyword ensures that one thread does not enter a critical section of code while another thread is in the critical section.
Does a critical section have to be same as the critical section?
Or does it mean:
The lock keyword ensures that one thread does not enter any critical section guarded by an object of code while another thread is in any critical section guarded by the same object. ?
class Program
{
static void Main(string[] args)
{
TestDifferentCriticalSections();
Console.ReadLine();
}
private static void TestDifferentCriticalSections()
{
Test lo = new Test();
Thread t1 = new Thread(() =>
{
lo.MethodA();
});
t1.Start();
Thread t2 = new Thread(() =>
{
lo.MethodB();
});
t2.Start();
}
}
public class Test
{
private object obj = new object();
public Test()
{ }
public void MethodA()
{
lock (obj)
{
for (int i = 0; i < 5; i++)
{
Thread.Sleep(500);
Console.WriteLine("A");
}
}
}
public void MethodB()
{
lock (obj)
{
for (int i = 0; i < 5; i++)
{
Thread.Sleep(500);
Console.WriteLine("B");
}
}
}
}
The question is confusingly worded and the answers so far are not particularly clear either. Let me rephrase the question into several questions:
(1) Does the lock statement ensure that no more than one thread is in the body of the lock statement at any one time?
No. For example:
static readonly object lock1 = new object();
static readonly object lock2 = new object();
static int counter = 0;
static object M()
{
int c = Interlocked.Increment(ref counter);
return c % 2 == 0 ? lock1 : lock2;
}
...
lock(M()) { Critical(); }
It is possible for two threads to both be in the body of the lock statement at the same time, because the lock statement locks on two different objects. Thread Alpha can call M() and get lock1, and then thread Beta can call M() and get lock2.
(2) Assuming that my lock statement always locks on the same object, does a lock statement ensure that no more than one "active" thread is in the body of the lock at any one time?
Yes. If you have:
static readonly object lock1 = new object();
...
lock(lock1) { Critical(); }
then thread Alpha can take the lock, and thread Beta will block until the lock is available before entering the lock body.
(3) Assuming that I have two lock statements, and both lock statements lock on the same object every time, does a lock statement ensure that no more than one "active" thread is in the body of either lock at any one time?
Yes. If you have:
static readonly object lock1 = new object();
...
static void X()
{
lock(lock1) { CriticalX(); }
}
static void Y()
{
lock(lock1) { CriticalY(); }
}
then if thread Alpha is in X and takes the lock, and thread Beta is in Y, then thread Beta will block until the lock is available before entering the lock body.
(4) Why are you putting "active" in "scare quotes"?
To call attention to the fact that it is possible for a waiting thread to be in the lock body. You can use the Monitor.Wait method to "pause" a thread that is in a lock body, and allow a blocked thread to become active and enter that lock body (or a different lock body that locks the same object). The waiting thread will stay in its "waiting" state until pulsed. At some time after it is pulsed, it rejoins the "ready" queue and blocks until there is no "active" thread in the lock. It then resumes at the point where it left off.
You put a lock on an object. If another thread tries to access a critical section marked by that object at the same time, it will block until the lock is removed/complete.
Example:
public static object DatabaseLck= new object();
lock (DatabaseLck) {
results = db.Query<T>(query).ToList();
}
Or
lock (DatabaseLck) {
results = db.Query<T>(string.Format(query, args)).ToList();
}
Neither one of those code blocks can be run at the same time BECAUSE they use the same lock object. If you used a different lock object for each, they could run at the same time.
It is one and the same critical section.
lock (synclock)
{
// the critical section protected by the lock statement
// Only one thread can access this at any one time
}
See lock Statement on MSDN:
The lock keyword marks a statement block as a critical section by obtaining the mutual-exclusion lock for a given object, executing a statement, and then releasing the lock.
Or does it mean: The lock keyword ensures that one thread does not enter any critical section of code while another thread is in any critical section. ?
No. It does not mean that. It means the critical section protected by that lock and that lock alone.
Update, following code example:
If you use a single object to lock on, it will lock all critical sections, causing other threads to block until released. In your code example, once the lock in MethodA has been entered, all other threads reaching that lock and the lock on MethodB will block until the lock is released (this is happening because you are locking on the same object in both methods).
It does not mean any, though you can protect 2 blocks of code from being entered by more than one thread at the same time by locking them both with the same object. This is a common paradigm -- you may want to lock your collection for both clears and writes.
No it means that another thread wont enter THE critical section protected by this lock statement.
The Critical section is only defined by the programmer, and in this case, you could replace it by : the section protected by a lock
So translation :
The lock keyword ensures that one thread does not enter a section of code protected by a lock while another thread is in this section of code (protected by a lock )
The critical section that it is talking about is the section guarded by the lock statements.
Any critical section that is locking on the same object will be blocked from getting access.
It is also important that your lock object be static, because the locks need to be locking (or trying to lock) on the same instance of the lock object.