Sign in to follow this  
Daniel Miller

[.net] locking in c#

Recommended Posts

Daniel Miller    218
edit: I was doing everything all wrong, but I still do not understand how to protect a variable from being accesse in another thread. Could you explain how? [Edited by - Daniel Miller on June 3, 2005 12:41:01 PM]

Share this post


Link to post
Share on other sites
turnpast    1011
Threading is a fairly large subject, here are some resources.

The easiest way to make a variable thread safe (if that is what you are asking) is to declare it with the volatile keyword.

Share this post


Link to post
Share on other sites
Daniel Miller    218
Actually, I was looking for the Monitor class, which locks a variable for a specific thread. I was looking at it so wrong you couldn't even imagine (I was trying to use 'lock' on a variable).

Share this post


Link to post
Share on other sites
Daniel Miller    218
Does Monitor grant exclusive access to an actual object on the heap?

edit: weird things are happenning when I try and use Monitor.Enter.

For one, when I try to lock a public field of an instance of a class, it highlights "for (int x = 0;" on the next line and then that a says that a 'System.ArgumentNullException' was thrown.

But that is only when I try to attach a monitor to the field itself. Attaching it to the entire object has no effect.


edit: Whenever I make a change, it works for the first run, then never works again.

edit2: It's now alternating between working and not working. When it doesn't work, the output is strangely uniform for something that should be somewhat random. It should be all '*' without any '#' (ignore the '%%%%%'), but when it doesn't work:

%%%%% * %%%%% # %%%%% * %%%%% * %%%%% # %%%%% * %%%%% * %%%%% # %%%%% * %%%%% *
%%%%% # %%%%% * %%%%% * %%%%% # %%%%% * %%%%% * %%%%% # %%%%% * %%%%% * %%%%% #
%%%%% * %%%%% * %%%%% # %%%%% * %%%%% * %%%%% # %%%%% * %%%%% * %%%%% # %%%%% *
%%%%% * %%%%% # %%%%% * %%%%% * %%%%% # %%%%% * %%%%% * %%%%% # %%%%% * %%%%% *
%%%%% # %%%%% * %%%%% * %%%%% # %%%%% * %%%%% * %%%%% # %%%%% * %%%%% * %%%%% #
%%%%% * %%%%% * %%%%% # %%%%% * %%%%% * %%%%% # %%%%% * %%%%% * %%%%% # %%%%% *
%%%%% * %%%%% # %%%%% * %%%%% * %%%%% # %%%%% * %%%%% * %%%%% # %%%%% * %%%%% *
%%%%% # %%%%% * %%%%% * %%%%% # %%%%% * %%%%% * %%%%% # %%%%% * %%%%% * %%%%% #
%%%%% * %%%%% * %%%%% # %%%%% * %%%%% * %%%%% # %%%%% * %%%%% * %%%%% # %%%%% *
%%%%% * %%%%% # %%%%% * %%%%% * %%%%% # %%%%% * %%%%% * %%%%% # %%%%% * %%%%% *
%%%%% # %%%%% * %%%%% * %%%%% # %%%%% * %%%%% * %%%%% # %%%%% * %%%%% * %%%%% #
%%%%% * %%%%% * %%%%% # %%%%% * %%%%% * %%%%% # %%%%% * %%%%% * %%%%% # %%%%% *
%%%%% * %%%%% # %%%%% * %%%%% * %%%%% # %%%%% * %%%%% * %%%%% # %%%%% * %%%%% *
%%%%% # %%%%% * %%%%% * %%%%% # %%%%% * %%%%% * %%%%% # %%%%% * %%%%% * %%%%% #
%%%%% * %%%%% * %%%%% # %%%%% * %%%%% * %%%%% # %%%%% * %%%%% * %%%%% # %%%%% *
%%%%% * %%%%% # %%%%% * %%%%% * %%%%% # %%%%% * %%%%% * %%%%% # %%%%% * %%%%% *
%%%%% # %%%%% * %%%%% * %%%%% # %%%%% * %%%%% * %%%%% # %%%%% * %%%%% * %%%%% #
%%%%% * %%%%% * %%%%% # %%%%% * %%%%% * %%%%% # %%%%% * %%%%% * %%%%% # %%%%% *


[Edited by - Daniel Miller on June 3, 2005 1:18:33 PM]

Share this post


Link to post
Share on other sites
jods    367
I would like to chime in to prevent confusion and errors.

I don't know what turnpast means exactly with "make a variable thread-safe", but to my sense, putting the "volatile" keyword doesn't solve all problems with multithreading. It should not be confused with Java's "synchronized".

"volatile" is a lightweight way to make some code thread-safe, but you have to carefully understand what it does and what this implies. It doesn't solve all multithreading scenarioes, and that's why there's the lock semantic.

For example, defining x as a volatile int will not make "x += 3" thread-safe (because it's not atomic). The result could be incorrect, if another thread reads/writes x after the reading but before the writing.

A few pointers:
C# specs, section 10.4.3 volatile fields. Explains what a volatile field is, and gives a small example of how it can be used to make some thread-safe code.

System.Threading.Interlocked class. Offers some atomic primitives (increment, exchange, ...) that are generally implemented in a lightweight fashion (i.e. using atomic CPU instructions).

C# lock keyword. Explains what the lock instruction is, what it does, and some examples. Note that the suggestion about what to lock on aren't that good, and I suggest you to read: Choosing what to lock on also.

System.Threading namespace. Contains other threading related primitives for synchronization. Look at classes Interlocked, Monitor, Mutex, ReaderWriterLock, ...

I know this is a lot of materials, but making efficient multithreading code is no simple issue.

Good luck,
jods

Share this post


Link to post
Share on other sites
Daniel Miller    218
Thank you, but I am trying to make a single object un accessable from other threads. I am having the problems I mentioned above when I do so (I'm using monitor).

Share this post


Link to post
Share on other sites
jods    367
Daniel, what about posting your code here ?

Monitor.Enter and Exit are used to build critical sections. That means section of code that are going to be executed by only one thread at a time. In C#, instead of calling Monitor directly, you can use the lock keyword. That's basically the same, but may be more readable. lock calls Monitor.Enter, add a try...finally block, and calls Monitor.Exit in the finally clause.

Enter is a blocking call that will "acquire" the object you pass to it. Which object you pass is totally irrelevant. Enter will block if another thread has already "acquired" the same object, until it releases it. A thread releases an object that it has acquired by calling Exit.

There is no way to grant "exclusive access" to an object in C#. You have to protect the sections of code that access this object instead (here encapsulation / thread-safe classes are an obvious benefit).

Share this post


Link to post
Share on other sites
Daniel Miller    218
Fixed the formatting, I think.

Main.cs:

using System;
using System.Threading;

namespace LockThreadingTest
{
public class MainClass
{
public static void Main()
{
Speaker speaker = new Speaker();
SpeakerUser user = new SpeakerUser(speaker);

Thread thread = new Thread(new ThreadStart(user.Run));
thread.Start();

Monitor.Enter(speaker);
for (int x = 0; x != 1000; ++x)
{
speaker.quote = "*";
Console.Write("%");
Console.Write("%");
Console.Write("%");
Console.Write("%");
Console.Write("%");
speaker.Speak();
}
Monitor.Exit(speaker);

thread.Abort();
thread.Join();

Console.Read();
}
}
}







Speaker.cs

using System;

namespace LockThreadingTest
{
public class Speaker
{
public void Speak()
{
Console.Write(" " + quote + " ");
}

public void SpeakForever()
{
while(true)
{
Console.Write(" " + quote + " ");
}
}

public string quote;
}
}




SpeakerUser.cs



[source  lang="c#"]
using System;
namespace LockThreadingTest
{
public class SpeakerUser
{
public SpeakerUser(Speaker speaker)
{
this.speaker = speaker;
}

public void Run()
{
while (true)
{
speaker.quote = "#";
}
}

private Speaker speaker;
}
}






That is the code as I have it.

I am trying to prevent speaker.quote from being over written in the other thread.

Share this post


Link to post
Share on other sites
jods    367
Uh... there is an obvious problem of conception / understanding here. It doesn't work like that.

Your Monitor code is completely useless. Monitor prevents several thread to execute some code (between Enter and Exit) concurrently.

You give your SpeakerUser a reference to Speaker, and then you execute:
speaker.quote = "#";

You say that you are trying to prevent the other thread to overwrite speaker.quote. What does this mean ? What is the expected behaviour of the code above ? Should it do nothing, throw, or what ?

Share this post


Link to post
Share on other sites
Daniel Miller    218
I think I figured it out. I was completely confused as to what monitor did (it really acts like lock). I was trying to keep SpeakerUser from changing the value of speaker.quote, but of course what I was doing didn't work. In actual cases, what I was trying to do can probably be accomplished simply by clocking sections of code.

Share this post


Link to post
Share on other sites
jods    367
Yes, lock is the same as Monitor.Enter and Exit. That's what I said before:
Quote:
In C#, instead of calling Monitor directly, you can use the lock keyword. That's basically the same, but may be more readable. lock calls Monitor.Enter, add a try...finally block, and calls Monitor.Exit in the finally clause.


I'm glad you could solve your problem.

Have a nice day,
jods

-EDIT-
One thing I forgot. lock/Monitor are used to prevent concurrent execution. If you want to set an execution ordering or dependencies, you can use ManualResetEvent or AutomaticResetEvent classes.
E.g., say you'd like the loop in main to print everything before the SpeakerUser changes the value of quote. Then create a global ManualResetEvent.

Before the SpeakerUser code, call WaitOne. This will block until another signals the event.
In the main code, after the printing loop, call Set. This will signal the event and unblock the other thread.
At this point, SpeakerUser can continue and change the quote, but the main thread has already done the printing.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this