I was testing thread-safety for better grasp and this is what I did :
I have a Type called ThreadSample
which has two methods and this where locking is happening :
internal class ThreadTime
{
public void doSomething(string message)
{
lock (this)
{
DialogResult t = MessageBox.Show(message);
Thread.Sleep(2000);
}
}
public void anotherLife(string message)
{
MessageBox.Show("This is coming from anotherLife method and and current threadNumber is " + message);
开发者_开发技巧 }
}
Basically the idea is when doSomething()
is called, it should lock the entire objects and other threads can even invoke anotherLife
method since they are waiting for other threads to release the lock.
This is the logic to simulate lock-release :
public partial class Form1 : Form
{
private ThreadTime time;
private Thread thread;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
thread = new Thread(new ThreadStart(workerThread));
time = new ThreadTime();
}
private void button1_Click(object sender, EventArgs e)
{
thread.Start();
//Thread.Sleep(1000);
time.anotherLife("Current thread is = " + "UI Thread");
}
private void workerThread()
{
//time.doSomething("Current thread is = " + Thread.CurrentThread.ManagedThreadId);
time.doSomething("Worker Thread");
}
}
As you can see in the code right below :
When Form
is being initialized, a new Thread
and ThreadSample
are created. Then when user clicks on the button1
, thread is started and the UIThread is reaching and invoking anotherLife
which is not thread-safe at first.
Anyways, the output is :
- There are two MessageBox shown at the same time.
What I was expecting is when the new Thread invokes doSomething()
, it gets the lock of the object and UIThread
waits for the lock to be released to be able to invoke anotherLife
method.
Can some one explain why?
Thanks.
What I was expecting is when the new Thread invokes doSomething(), it gets the lock of the object and UIThread waits for the lock to be released to be able to invoke anotherLife method.
UIThread won't wait for a lock to be released before allowing anotherLife
to proceed because anotherLife
is not performing a lock. Both threads have to run into a lock
statement (locking on the same object) in order to get the behavior you're looking for. Try modifying it to something like:
public void anotherLife(string message)
{
lock (this)
{
MessageBox.Show("This is coming from anotherLife method and and current threadNumber is " + message);
}
}
Well, lock(this)
or lock(someThing)
can be a bit of a misleading metaphor.
There is nothing being done 'to' this
, but rather the argument to lock
is used as a token. All threads accessing a specific resource must use the same token (object) to request access, otherwise your code is broken.
That is why frequently a helper object is used:
private List<string> myList = ...;
private object myLock = new object();
lock(myLock)
{
myList.Add("foo");
}
This scheme only works if all threads lock on myLock
before changing myList
.
It is considered a 'best practice` because it is not guaranteed that a List<> is safe to lock on.
Only your thread observes the lock
You need to change
private void button1_Click(object sender, EventArgs e)
{
thread.Start();
//Thread.Sleep(1000);
time.anotherLife("Current thread is = " + "UI Thread");
}
to
private void button1_Click(object sender, EventArgs e)
{
thread.Start();
//Thread.Sleep(1000);
lock(time)
{
time.anotherLife("Current thread is = " + "UI Thread");
}
}
Based on your code, it seems you think putting a lock on an object means that object can't be accessed by anything else. That is not the case. A lock on an object just means another lock may not be put on the object until the first lock is released.
You access the object from two places in your code, one in the thread and the other in the button event. You need a lock in both places.
精彩评论