Question regarding the operation of lock ( )

J

Jim

Hi all,

I have a question regarding the operation of critical sections within a
class definition. Below is an example class that contains two methods that
perform locks on the current instance. The methods themselves are not
tagged with the [MethodImlp(MethodImplOptions.Synchronized)] attribute. The
object is shared across multiple threads.

Are the critical sections in Method1() and Method2() mutually exclusive?
ie. If "Thread A" has acquired the lock and is executing within the
critical section of Method1(), will "Thread B" wait for the lock to be
released before it can execute the critical section in Method2()?

Thanks,

Jim


class A
{
public A {}

public void Method1 ()
{
lock (this)
{
...
}
}


public void Method2 ()
{
lock (this)
{
...
}
}
}
 
J

Jon Skeet [C# MVP]

Jim said:
I have a question regarding the operation of critical sections within
a class definition. Below is an example class that contains two
methods that perform locks on the current instance. The methods
themselves are not tagged with the
[MethodImlp(MethodImplOptions.Synchronized)] attribute. The object is
shared across multiple threads.

Are the critical sections in Method1() and Method2() mutually exclusive?
Yes.

ie. If "Thread A" has acquired the lock and is executing within the
critical section of Method1(), will "Thread B" wait for the lock to be
released before it can execute the critical section in Method2()?

Yes.

I would advise against locking on "this" though:
http://www.pobox.com/~skeet/csharp/multithreading.html#lock.choice
 
J

Jim

Thanks, Jon.

Thank you for confirming the operation of lock. The article you
referenced is a very interesting read and a very good point about using
private members for locking. I hadn't thought about synchronizing on "this"
in the context of separating the internal synchronization of the class from
external sychronization options.

I appear to be having a problem with the situation that I described.
"Thread A" is the main application thread. "Thread B" is a worker thread
that reads GPS data from a comm port and displays the data in a text box.
"Class A" inherits from System.Windows.Forms.Form. Below is psuedocode that
more closely described the situation, though it is much simplified.

At application exit, "Thread A" calls OnClose() and "Thread B" is still
periodically calling DisplayLine(). Whenever this occurs, both threads
hang. Whichever thread has the lock is hung in a method call to one of the
form's controls (like button.Enabled = false).

I thought that perhaps locking on "this" was creating the deadlock, so I
added a private synchronization object. But, the deadlock still occurs. I
also tried, moving the synchroniztion to the GPS class, but also no luck.

Any ideas or am I just making a stupid mistake.

Thanks again for your help,

Jim


class GPS_Terminal_Form : System.Windows.Forms.Form
{
private Object m_monitor = new Object();

public GPS_Terminal_Form {}

public void DisplayLine ( string s )
{
lock ( m_monitor )
{
textbox.AppendText( s );
...
}
}


public void OnClose()
{
lock ( m_monitor )
{
button.Enabled = false;
...
}
}
}


class GPS
{
private GPS_Terminal_Form m_termForm = new GPS_Terminal_Form();


private void CloseCommPort()
{
m_termForm.OnClose();
...
}


private void ReadThread()
{
...
m_termForm.DisplayLine( s );
}
}







Jon Skeet said:
Jim said:
I have a question regarding the operation of critical sections within
a class definition. Below is an example class that contains two
methods that perform locks on the current instance. The methods
themselves are not tagged with the
[MethodImlp(MethodImplOptions.Synchronized)] attribute. The object is
shared across multiple threads.

Are the critical sections in Method1() and Method2() mutually exclusive?
Yes.

ie. If "Thread A" has acquired the lock and is executing within the
critical section of Method1(), will "Thread B" wait for the lock to be
released before it can execute the critical section in Method2()?

Yes.

I would advise against locking on "this" though:
http://www.pobox.com/~skeet/csharp/multithreading.html#lock.choice
 
S

Scott Allen

J

James Cassidy

Thanks Scott,

Appearantly, I should have kept reading this morning:) I am new to the
..NET/C#, so the clue is greatly appreciated. I was unaware of the Invoke
functionality.

Jim
 
J

Jon Skeet [C# MVP]

James Cassidy said:
Appearantly, I should have kept reading this morning:) I am new to the
.NET/C#, so the clue is greatly appreciated. I was unaware of the Invoke
functionality.

FWIW, it's far too big an article (or issue!) to take in in a single
go.

If it's any help to you, I'm refactoring it into different pages (with
a printable version, eventually). There are still a few extra bits and
pieces I want to add, and it's still rough around the edges in the new
version, but it's available at:

http://www.pobox.com/~skeet/csharp/threads

if you want.

(And yes, part of the reason for the change was to get a shorter URL :)
 
J

Jim

Jon,

It is the issue that is big. Your article is outstanding and I have
advised my compatriots at work to read it, as should anyone who stumbles
across this thread. Thank you very much for your efforts.

The final (hopefully:) solution for my problem involved an unexpected
behavior from InvokeRequired in my form class. InvokeRequired always
returned false when the form was not visible. I changed my test from "this"
to testing one of the controls in my form. Calling InvokeRequired on a
control, when the form was not visible, correctly returned true when not in
the main thread.

Since I made this change, I have not found my worker thread
inapropriately modifying GUI elements. I have breakpoints set with the
condition of Thread.CurrentThread != GUI Thread. This seems to be a nice
way to trap on the worker thread.

Thanks again,

Jim
 
J

Jon Skeet [C# MVP]

Jim said:
It is the issue that is big. Your article is outstanding and I have
advised my compatriots at work to read it, as should anyone who stumbles
across this thread. Thank you very much for your efforts.

My pleasure - glad it's helped.
The final (hopefully:) solution for my problem involved an unexpected
behavior from InvokeRequired in my form class. InvokeRequired always
returned false when the form was not visible. I changed my test from "this"
to testing one of the controls in my form. Calling InvokeRequired on a
control, when the form was not visible, correctly returned true when not in
the main thread.

Yikes. That's a pretty nasty issue. I'll investigate it and see if I
can find out any more.
Since I made this change, I have not found my worker thread
inapropriately modifying GUI elements. I have breakpoints set with the
condition of Thread.CurrentThread != GUI Thread. This seems to be a nice
way to trap on the worker thread.

Good good. You really shouldn't need to though - it's a horrible hack
to have to call it on a control rather than the form.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top