I test simple code
static Thread _readThread = null;
static private Object thisLock = new Object();
static int a = 1;
private static void ReadComPort()
{
lock (thisLock)
{
for (int i = 0; i < 3; i++)
{
Console.WriteLine(Thread.CurrentThread.Name + " " + a++.ToString());
Thread.Sleep(1000);
}
}
}
static void Main(string[] args)
{
for (int i = 0; i < 3; i++)
{
_readThread = new Thread(new ThreadStart(ReadComPort));
_readThread.IsBackground = true;
_readThread.Name = i.ToString();
_readThread.Start();
//Thread.Sleep(50);
}
Console.WriteLine("End");
Console.ReadKey();
}
but why is the sequence of execution and the launching of threads chaotic:
0,2,1 Why?
Console output:
0 1
End
0 2
0 3
2 4
2 5
2 6
1 7
1 8
1 9
Because you can't expect threads to start or run in a specific order. The OS schedules threads the way it wants to. Sometimes it puts a thread on hold, executes another one, before coming back to the original one.
Here you see that the threads start almost at the same time. Obviously (from the output) thread 0 wins it to the first lock. Then, by pure chance, thread 2 gets by the lock earlier than thread 1. This could have gone entirely different since the threads are created shortly after each other. As said: there is no guarantee.
Lock does not guarantee the order : Does lock() guarantee acquired in order requested?
Also, in your code, you should wait your threads to finish at the end of your for loop in order to not have "end" at the beginning - if you press a key, you will exit while your thread are still running, and you may have unexpected behaviour.
Read the C# reference carefully.
https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/lock-statement
There, you cannot find anything about the order of threads entering the lock block.
Related
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 am experimenting with the signaling constructs of .NET and tried to do a simple coordination between two threads, however something is wrong and the results are all over the place with the program sometimes locking up. I guess there is some sort of race condition going on, but would like for someone to explain what's happening.
private static readonly AutoResetEvent manual = new AutoResetEvent(false);
private static int num;
public static async Task Main()
{
await Task.WhenAll(Task.Run(Method1), Task.Run(Method2));
}
private static void Method1()
{
num = 100;
manual.Set();
manual.WaitOne();
num -= 1000;
manual.Set();
}
private static void Method2()
{
manual.WaitOne();
var into = num;
num += into / 2;
manual.Set();
manual.WaitOne();
Console.WriteLine($"final value of num {num}");
}
Yes, this is a race condition.
Method 1 Begins
Method 2 cant start before Method 1 because it calls WaitOne in the beginning and the AutoResetEvent is not in the signaled state
Method 1 assigns num = 100
Method 1 sets AutoResetEvent. This notifies a waiting thread that an event has occurred.
Rest of work will be divided into multiple Scenarios.
Scenario 1:
Method 1 calls WaitOne, consumes AutoResetEvent signaled state and goes to the next line, AutoResetEvent resets.
Method 1 decreases num by 1000 (num = -900 now)
Method 1 signals AutoResetEvent
Method 2 can start cause AutoResetEvent is signlaed. AutoResetEvent resets after Method 2 getting notified.
Method 2 assigns into = num (into = -900)
Method 2 increases num by (into / 2) which makes the final result of num = -1350 (num = -900 - 450)
Method 2 signals AutoResetEvent
Method 2 consumes AutoResetEvent signaled state
Method 2 prints final value
The result is -1350 and the program terminates because both tasks finished in this Scenario.
Scenario 2:
Instead of method 1, Method 2 calls WaitOne and continues. AutoResetEvent resets.
Method 1 cant go to the next line because it is blocked by WaitOne
Method 2 assigns num to into (into = 100 now)
Method 2 increases num by into/2 (num = 100 + 50 = 150)
Method 2 sets AutoResetEvent.
Here, Scenario 2 will be divided into multiple Scenarios. Scenarios2-1 and Scenarios2-2
Scenario 2-1:
Method 1 gets notified and decrease num by 1000 (num = 150 - 1000 = -850)
Method 1 sets AutoResetEvent.
Method 2 gets notified and prints the result.
The result is -850 and the program terminates, because both tasks finished in this Scenario.
Scenario 2-2:
Method 2 gets notified and prints the result.
Method 1 will be blocked until someone somewhere set the AutoResetEvent.
The result is 150 and the program does NOT terminate, because the first task is not finished yet.
What I want to do
I have some threads (e.g. Thread 1, Thread 2, Thread 3), and a queue of integers (e.g. 1, 2, 3).
Every one second, I want to pause currently running thread, and pop from a queue, and run a thread that has the same id.
For example:
Let's say I have an array of thread, and an integer that holds currently executing thread.
int[] myThread; //1, 2, 3
ManualResetEventSlim[] mre;
executing = 1;
Queue myQueue; //2, 3
Time 0:01 //Thread 1 is running
Time 0:02 mre[executing].Wait();
myQueue.Enqueue(executing);
int nextThread = myQueue.Dequeue(); //say 2
mre[nextThread].Set();
executing = nextThread;
Time 0:03 //Same thing as at 0:02...
Time 0:04 //Same above
Time 0:05 //Same above
and want outputs that look like this:
Time 0:01 I'm 1
I'm 1
I'm 1
Time 0:02 I'm 2 // thread 2 was selected
I'm 2
I'm 2
Time 0:03 I'm 3 // thread 3 was selected
I'm 3
I'm 3
Time 0:04 I'm 2 // thread 2 was selected
I'm 2
I'm 2
What I'm doing
I have a main file that defines the action:
static void Main()
{
CreateThread(Action, n);
}
public static void Action(int pid)
{
for(int i=0; i<100000; i++)
{
Trace.WriteLine("I'm "+ pid);
}
}
Problem
The problem is that once a thread is set with Set(), it cannot be blocked again with Wait(). Because of that, each thread just keeps executing the whole Action method until it's done.
and outputs look like this:
Time 0:01 I'm 1 //Only Thread 1 is unblocked
I'm 1
I'm 1
Time 0:02 I'm 2 //Thread 2 was unblocked.
I'm 1 //Thread 1 is not blocked, so it keeps printing
I'm 2
Time 0:03 I'm 3 //Thread 3 was unblocked.
I'm 1 //Thread 1 is not blocked
I'm 2 //Thread 2 is not blocked either
I've been working on this for a while and am stuck. I really appreciate any help.
Im not sure if I understand the problem, but I'd change Action() so that it takes an instance of ThreadData. You'll need it to check whether the MRE is set. If so, break out of the iteration and let the framework take care of cleaning up after the thread.
public static void Action(ThreadData threadData)
{
for (int i = 0; i < 100000; i++)
{
if (threadData.Mre.IsSet)
{
break;
}
Trace.WriteLine("I'm " + threadData.Pid);
}
}
EDIT
You might not realize it, but you're probably using the same instance of MRE for each thread. Each thread references the mre variable. Who is to say that the thread starts before you set mre to a new instance? Spoiler: it doesn't.
Using the lock statement, one can "ensure that one thread does not enter a critical section of code while another thread is in the critical section. If another thread tries to enter a locked code, it will wait, block, until the object is released."
What if the behaviour I want is that if another thread tries to enter the locked code, it will just skip the whole code (instead of waiting the lock to be released)? An idea that come to my mind is using a flag, something like
if(flag) return;
flag = true;
//do stuff here
flag =false;
But I know this is not safe because two threads can pass the first line before anyone set to true, or the flag being never set to false in case of exceptions.. Can you suggest an improvement or an alternative?
Use this overload of Monitor.TryEnter, which lets you specify a timeout.
Attempts, for the specified amount of time, to acquire an exclusive
lock on the specified object.
Return Value Type: System.Boolean true if the current thread acquires
the lock without blocking; otherwise, false.
In your case, you probably want to use a timeout of close to TimeSpan.Zero.
If you don't want the thread attempting to take the lock to wait for any length of time, you can just this overload of Monitor.TryEnter, which does not accept a TimeSpan argument. This method will immediately return without waiting - very close to the sentiment of the flag technique you are trying to use.
You need Semaphores with a limit 1 and timeout period 0 miliseconds
By using Semaphore you can say that only a limited number of threads can access a piece of code at a time.
See this sample for how to use it
You need to use this method for waiting
bool WaitOne(int millisecondsTimeout)
specify timeout period = 0; in this way your waiting threads will wait 0 second which means they will simply skip the code
Example
class SemaphoreExample
{
// Three reserved slots for threads
public static Semaphore Pool = new Semaphore(1, 0);
public static void Main(string[] args)
{
// Create and start 20 threads
for (int i = 0; i < 20; i++)
{
Thread t = new Thread(new ThreadStart(DoWork));
t.Start();
}
Console.ReadLine();
}
private static void DoWork()
{
// Wait 0 miliseconds
SemaphoreExample.Pool.WaitOne(0);
#region Area Protected By Semaphore
Console.WriteLine("Acquired slot...");
for (int i = 0; i < 10; i++)
{
Console.WriteLine(i + 1);
}
Console.WriteLine("Released slot...");
#endregion
// Release the semaphore slot
SemaphoreExample.Pool.Release();
}
}
you can use Monitor.TryEnter
http://msdn.microsoft.com/en-us/library/dd289679.aspx
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.