I would like to - for obscure reasons thou shall not question - start a lock in a method, and end it in another. Somehow like:
object mutex = new object();
void Main(string[] args)
{
lock (mutex)
{
doThings();
}
}
Would have the same behaviour as:
object mutex = new object();
void Main(string[] args)
{
Foo();
doThings();
Bar();
}
void Foo()
{
startLock(mutex);
}
void Bar()
{
endlock(mutex);
}
The problem is that the lock keyword works in a block syntax, of course. I'm aware that locks are not meant to be used like this, but I'm more than open to the creative and hacky solutions of S/O. :)
private readonly object syncRoot = new object();
void Main(string[] args)
{
Foo();
doThings();
Bar();
}
void Foo()
{
Monitor.Enter(syncRoot);
}
void Bar()
{
Monitor.Exit(syncRoot);
}
[Edit]
When you use lock, this is what happening under the hood in .NET 4:
bool lockTaken = false;
try
{
Monitor.Enter(syncRoot, ref lockTaken);
// code inside of lock
}
finally
{
if (lockTaken)
Monitor.Exit(_myObject);
}
Related
I wonder why SpinLock doesn't support recursion.
Let's say I have a simple program with Monitor that locks and releases a block of instructions in a recursive way:
class Program
{
private static readonly object lockObj = new object();
private static void Recursion(int x)
{
bool lockWasTaken = false;
try
{
Monitor.Enter(lockObj, ref lockWasTaken);
Console.WriteLine(x);
}
finally
{
if (x > 0)
{
Recursion(x - 1);
}
if (lockWasTaken) Monitor.Exit(lockObj);
}
}
static void Main(string[] args)
{
Recursion(5);
Console.ReadKey();
}
}
If I do the same with SpinLock:
class Program
{
private static SpinLock sl = new SpinLock(true);
private static void Recursion(int x)
{
bool lockWasTaken = false;
try
{
sl.Enter(ref lockWasTaken);
Console.WriteLine(x);
}
finally
{
if (x > 0)
{
Recursion(x - 1);
}
if (lockWasTaken) sl.Exit();
}
}
static void Main(string[] args)
{
Recursion(5);
Console.ReadKey();
}
}
It throws an excpetion which says the calling thread already has a lock - and it is obviously true.
But my question is why Monitor can acquire a lock multiple times by the same thread while SpinLock cannot?
I can't find any reasons why a thread that has already locked a critical section can't enter it again.
I am having issue with my singleton class in multi threading environment. This sample program calls method A & B on separate threads. Normally this works ok.
In some cases as shown in the last result at bottom
method A call starts
method B call starts
method B call ends
then method A call ends<---- why is this happening out of order ?
Is this because I am not performing double lock ?
How do I ensure that this does not happen ?
Caller
class Program
{
static void Main(string[] args)
{
ThreadPool.QueueUserWorkItem(new WaitCallback(CallonThread));
Singleton.Instance.Test("B");
Console.ReadKey();
}
static void CallonThread(object a)
{
Singleton.Instance.Test("A");
}
}
Singleton Class
public class Singleton
{
static readonly object Padlock = new object();
private static Singleton _instance;
protected Singleton()
{
}
public static Singleton Instance
{
get
{
lock (Padlock)
{
if (_instance == null)
{
_instance = new Singleton();
}
return _instance;
}
}
}
public void Test(string id)
{
if (id == "A")
{
new Data().MethodA();
}
else
{
new Data().MethodB();
}
}
}
Data class
public class Data
{
public void MethodA()
{
Console.WriteLine("Start Method A");
Console.WriteLine("End Method A");
}
public void MethodB()
{
Console.WriteLine("Start Method B");
Console.WriteLine("End Method B");
}
}
Result
This would work to stop MethodA and MethodB from executing simultaneously:
public class Data
{
private static object _padlock = new object();
public void MethodA()
{
lock (_padlock)
{
Console.WriteLine("Start Method A");
Console.WriteLine("End Method A");
}
}
public void MethodB()
{
lock (_padlock)
{
Console.WriteLine("Start Method B");
Console.WriteLine("End Method B");
}
}
}
I create an example about thread,
I know that use lock could avoid thread suspending at critical section, but I have two questions.
1.Why my program get stuck if I use Thread.Sleep?
In this example, I add sleep to two thread.
Because I wish the console output more slowly, so I can easily see if there's anything wrong.
But if I use Thread.Sleep() then this program will get stuck!
2.What situation should I use Thread.Sleep?
Thanks for your kind response, have a nice day.
class MyThreadExample
{
private static int count1 = 0;
private static int count2 = 0;
Thread t1;
Thread t2;
public MyThreadExample() {
t1 = new Thread(new ThreadStart(increment));
t2 = new Thread(new ThreadStart(checkequal));
}
public static void Main() {
MyThreadExample mt = new MyThreadExample();
mt.t1.Start();
mt.t2.Start();
}
void increment()
{
lock (this)
{
while (true)
{
count1++; count2++;
//Thread.Sleep(0); stuck when use Sleep!
}
}
}
void checkequal()
{
lock (this)
{
while (true)
{
if (count1 == count2)
Console.WriteLine("Synchronize");
else
Console.WriteLine("unSynchronize");
// Thread.Sleep(0);
}
}
}
}
Please take a look at these following codes. Never use lock(this), instead use lock(syncObj) because you have better control over it. Lock only the critical section (ex.: only variable) and dont lock the whole while loop. In method Main, add something to wait at the end "Console.Read()", otherwise, your application is dead. This one works with or without Thread.Sleep. In your code above, your thread will enter "Increment" or "Checkequal" and the lock will never release. Thats why, it works only on Increment or Checkequal and never both.
internal class MyThreadExample
{
private static int m_Count1;
private static int m_Count2;
private readonly object m_SyncObj = new object();
private readonly Thread m_T1;
private readonly Thread m_T2;
public MyThreadExample()
{
m_T1 = new Thread(Increment) {IsBackground = true};
m_T2 = new Thread(Checkequal) {IsBackground = true};
}
public static void Main()
{
var mt = new MyThreadExample();
mt.m_T1.Start();
mt.m_T2.Start();
Console.Read();
}
private void Increment()
{
while (true)
{
lock (m_SyncObj)
{
m_Count1++;
m_Count2++;
}
Thread.Sleep(1000); //stuck when use Sleep!
}
}
private void Checkequal()
{
while (true)
{
lock (m_SyncObj)
{
Console.WriteLine(m_Count1 == m_Count2 ? "Synchronize" : "unSynchronize");
}
Thread.Sleep(1000);
}
}
}
Thread is a little bit old style. If you are a beginner of .NET and using .NET 4.5 or above, then use Task. Much better. All new multithreading in .NET are based on Task, like async await:
public static void Main()
{
var mt = new MyThreadExample();
Task.Run(() => { mt.Increment(); });
Task.Run(() => { mt.Checkequal(); });
Console.Read();
}
I need to pass an object to another object. I know I have to pass c to t1. How do I do this
Thread t = new Thread(t1);
t.Start();
private static void t1(Class1 c)
{
while (c.process_done == false)
{
Console.Write(".");
Thread.Sleep(1000);
}
}
Ok guys, everybody is missing the point the object is being used outside the thread as well. This way, it must be synchronized to avoid cross-thread exceptions.
So, the solution would be something like this:
//This is your MAIN thread
Thread t = new Thread(new ParameterizedThreadStart(t1));
t.Start(new Class1());
//...
lock(c)
{
c.magic_is_done = true;
}
//...
public static void t1(Class1 c)
{
//this is your SECOND thread
bool stop = false;
do
{
Console.Write(".");
Thread.Sleep(1000);
lock(c)
{
stop = c.magic_is_done;
}
while(!stop)
}
}
Hope this helps.
Regards
You could simply do:
Thread t = new Thread(new ParameterizedThreadStart(t1));
t.Start(new Class1());
public static void t1(object c)
{
Class1 class1 = (Class1)c;
...
}
MSDN: ParameterizedThreadStart Delegate
Or even better:
Thread thread = new Thread(() => t1(new Class1()));
public static void t1(Class1 c)
{
// no need to cast the object here.
...
}
This approach permits multiple arguments and does not require you to cast the object to the desired class/struct.
private static void DoSomething()
{
Class1 whatYouWant = new Class1();
Thread thread = new Thread(DoSomethingAsync);
thread.Start(whatYouWant);
}
private static void DoSomethingAsync(object parameter)
{
Class1 whatYouWant = parameter as Class1;
}
I post my understanding of C# lock as follows, please help me validate whether or not I get it right.
public class TestLock
{
private object threadLock = new object();
...
public void PrintOne()
{
lock (threadLock)
{
// SectionOne
}
}
public void PrintTwo()
{
lock (threadLock)
{
// SectionTwo
}
}
...
}
Case I> Thread1 and Thread2 simultaneously try to call PrintOne.
Since PrintOne is guarded by the instance lock, at any time, only
one thread can exclusively enter the SectionOne.
Is this correct?
Case II> Thread1 and Thread2 simultaneously try to call PrintOne and PrintTwo
respectively (i.e. Thread1 calls PrintOne and Thread2 calls PrintTwo)
Since two print methods are guarded by the same instance lock, at any time,
only one thread can exclusively access either SectionOne or SectionTwo, but NOT both.
Is this correct?
1 and 2 are true only if all your threads use the same instance of the class. If they use different instances, then both cases are false
Sample
public class TestLock
{
private object threadLock = new object();
public void PrintOne()
{
lock (threadLock)
{
Console.WriteLine("One");
var f = File.OpenWrite(#"C:\temp\file.txt"); //same static resource
f.Close();
}
}
public void PrintTwo()
{
lock (threadLock)
{
Console.WriteLine("Two");
var f = File.OpenWrite(#"C:\temp\file.txt"); //same static resource
f.Close();
}
}
}
And testing code
static void Main(string[] args)
{
int caseNumber = 100;
var threads = new Thread[caseNumber];
for (int i = 0; i < caseNumber; i++)
{
var t = new Thread(() =>
{
//create new instance
var testLock = new TestLock();
//for this instance we safe
testLock.PrintOne();
testLock.PrintTwo();
});
t.Start();
//once created more than one thread, we are unsafe
}
}
One of the possible solutions is to add a static keyword to the locking object declaration and methods that use it.
private static object threadLock = new object();
UPDATE
Good point made by konrad.kruczynski
..."thread safety" is also assumed from
context. For example, I could take
your file opening code and also
generate exception with static lock -
just taking another application
domain. And therefore propose that OP
should use system-wide Mutex class or
sth like that. Therefore static case
is just inferred as the instance one.
Case I: Check ✓
Case II: Check ✓
Don't forget that locking is only one way of thread synchronization. For other userfull methods, read: Thread Synchronization
Straight from MSDN sample:
public class TestThreading
{
private System.Object lockThis = new System.Object();
public void Process()
{
lock (lockThis)
{
// Access thread-sensitive resources.
}
}
}
Yes and yes. Cases are correct.
Your understanding is 100% correct. So if, for instance, you wanted to allow entry into the two methods separately you would want to have two locks.
Yes, you're correct in both counts.
here are the basics (more or less)
1) use instance locks for instance data
public class InstanceOnlyClass{
private int callCount;
private object lockObject = new object();
public void CallMe()
{
lock(lockObject)
{
callCount++;
}
}
}
2) use static locks for static data
public class StaticOnlyClass{
private int createdObjects;
private static object staticLockObject = new object();
public StaticOnlyClass()
{
lock(staticLockObject)
{
createdObjects++;
}
}
}
3) if you are protecting static and instance data use separate static and instance locks
public class StaticAndInstanceClass{
private int createdObjects;
private static object staticLockObject = new object();
private int callCount;
private object lockObject = new object();
public StaticAndInstanceClass()
{
lock(staticLockObject)
{
createdObjects++;
}
}
public void CallMe()
{
lock(lockObject)
{
callCount++;
}
}
}
based on this your code is fine if you are accessing instance data but unsafe if you are modifying static data