Suggestion for C#

A

Allan Ebdrup

I have a suggestion for C#
I would like reader/writer locks to be built in to the language.
When you want to aquire a loct on an object o you write
lock(o)
{
...//critical region
}

I would like to be able to write:
readlock(o)
{
...//critical region that only reads shared data
}

Behind the scenes, the first time readlock(o) was called, the locking
mechanism on o would be upgraded to a reader/writer lock and any active,
queued or future locks on o acqired by using lock(o) would become writer
locks.
That way there would be no difference for the programmer between usind a
reader/write lock and a normal lock, all you would need to know would be
that if you want to read and write shared data you use lock(o) and if you
only want to read shared data you just use readlock(o).

It may be feasible to downgrade the reader/writer lock to a normal lock
again if only lock(o) has been used for a long time with no readlock(o)'s
beeing called.

Reader/writer locks are very common and this approach would not force the
programmer to choose between a normal lock or a reader/writer lock, they
would be the same. Furthermore with my suggestion there would be no need for
creating a reader/writer lock object and creating try finally blocks etc.
The syntax is much easier to use.

If this is not the right place to post my suggestion, where do I send my
suggestion?

Kind Regards,
Allan Ebdrup
 
J

Jon Skeet [C# MVP]

I have a suggestion for C#
I would like reader/writer locks to be built in to the language.

I'd definitely disagree with that idea. I'd prefer locks not to be
part of the language at all - the "using" statement with appropriate
locking types is all that's required.

Reader/writer locks are very common

I can't remember the last time I used one, and I've done plenty of
multi-threaded code. Normally you can release the lock sufficiently
quickly that it's more efficient to just use a "normal" lock than to
use the heavier ReaderWriterLock. There's going to be a slimmer RW-
lock in .NET 3.5, but even so, I wouldn't want it in the language.
Where possible, the language should (IMO) avoid having dependencies on
the framework. There are exceptions, but they should be tightly
controlled.
Furthermore with my suggestion there would be no need for
creating a reader/writer lock object and creating try finally blocks etc.
The syntax is much easier to use.

A "using" statement is very easy to use.
See http://pobox.com/~skeet/csharp/miscutil/usage/locking.html for an
example - it could easily be expanded to have methods which take out a
ReaderWriter lock, or to have different types which would do that
appropriately.
If this is not the right place to post my suggestion, where do I send my
suggestion?

connections.microsoft.com is the normal place for suggestions and bug
reports. It's a good idea to get peer review on newsgroups first
though, so the suggestion can be "tuned" before submission.

Jon
 
J

Jon Skeet [C# MVP]

Just thinking about this further:

Behind the scenes, the first time readlock(o) was called, the locking
mechanism on o would be upgraded to a reader/writer lock and any active,
queued or future locks on o acqired by using lock(o) would become writer
locks.

How would you expect that to work? The C# compiler still has to
produce "normal" framework code - if this is just syntactic sugar,
could you write the current C# equivalent which would upgrade the lock
in one thread from a simple monitor lock to a reader/writer lock when
a read-only lock was required in a different thread?

Jon
 
M

Marc Gravell

It is certainly a valid place to *discuss* it, but "connect" is
probably better for a proposal - but this would need a lot more
work... for instance, there is a big difference between how
ReaderWriterLock and Monitor (=lock at the moment) work - Monitor uses
part of the targetted object, but ReaderWriterLock is itself an
object. The two would not be compatible at all.

Monitor tends to be significantly more lightweight, so a syntax change
for this to use a "write" ReaderWriterLock would be a huge change -
but that is the only way it could possibly be compatible when you
consider re-entrancy, sub methods etc. Likewise, this wouldn't support
Pulse etc.

In short - I can't see it being feasible, and in most cases I can't
see a reason to try. In most scenarios, Monitor is more than adequate.
In those scenarios where you really do want parallel concurrent
access, the existing ReaderWriterLock syntax works. I can't remember
the "who" or the exact quote, but a good rule of thumb is: if you want
to make a change like this, it had better be *much* better, otherwise
it isn't worth it. In this case, I'm not sure that it is.

IMHO

Marc
 
M

Mark Rae

I'd definitely disagree with that idea. I'd prefer locks not to be
part of the language at all - the "using" statement with appropriate
locking types is all that's required.

Agreed 100%.
I can't remember the last time I used one, and I've done plenty of
multi-threaded code.

Likewise, on both counts...
 
A

Allan Ebdrup

Jon Skeet said:
I'd definitely disagree with that idea. I'd prefer locks not to be
part of the language at all - the "using" statement with appropriate
locking types is all that's required.



I can't remember the last time I used one, and I've done plenty of
multi-threaded code. Normally you can release the lock sufficiently
quickly that it's more efficient to just use a "normal" lock than to
use the heavier ReaderWriterLock. There's going to be a slimmer RW-
lock in .NET 3.5, but even so, I wouldn't want it in the language.
Where possible, the language should (IMO) avoid having dependencies on
the framework. There are exceptions, but they should be tightly
controlled.

I see what you mean, I do use reader/writer locks for caching data that is
read very often in somewhat heavy operations and very seldom written. I
still like the idea of not having to choose wether you use a normal lock or
a reader/writer lock, and just upgrading the locking mecanism if needed.
A "using" statement is very easy to use.
See http://pobox.com/~skeet/csharp/miscutil/usage/locking.html for an
example - it could easily be expanded to have methods which take out a
ReaderWriter lock, or to have different types which would do that
appropriately.

good example. I'm not sure what mean by the last part. Do you mean that you
could make code that upgrades from a normal lock to a reader/writer lock?

Kind Regards,
Allan Ebdrup
 
A

Allan Ebdrup

Jon Skeet said:
Just thinking about this further:



How would you expect that to work? The C# compiler still has to
produce "normal" framework code - if this is just syntactic sugar,
could you write the current C# equivalent which would upgrade the lock
in one thread from a simple monitor lock to a reader/writer lock when
a read-only lock was required in a different thread?

I'm pretty sure it could be done. But I don't have a solution in mind.
 
J

Jon Skeet [C# MVP]

I see what you mean, I do use reader/writer locks for caching data that is
read very often in somewhat heavy operations and very seldom written.

But how long does fetching the data take anyway, and how much
concurrency do you expect? If it's quick, it could well be that using
a ReaderWriter lock is still more expensive than a plain exclusive
monitor lock.
I still like the idea of not having to choose wether you use a normal lock or
a reader/writer lock, and just upgrading the locking mecanism if needed.

It would be a nice idea if it were feasible - but I don't *think* it
is.
good example. I'm not sure what mean by the last part. Do you mean that
you could make code that upgrades from a normal lock to a reader/writer
lock?

I don't think it could upgrade an existing, held lock into a reader/
writer lock. With *very* carefully defined semantics it might be
possible to work something out, but I'm not entirely sure. I don't
think it's worth the extra work though, personally.

Jon
 
M

Moty Michaely

Just thinking about this further:



How would you expect that to work? The C# compiler still has to
produce "normal" framework code - if this is just syntactic sugar,
could you write the current C# equivalent which would upgrade the lock
in one thread from a simple monitor lock to a reader/writer lock when
a read-only lock was required in a different thread?

Jon

Jon,

I agree 100%.
Where possible, the language should (IMO) avoid having dependencies on
the framework. There are exceptions, but they should be tightly
controlled.

I would say that the language should try to avoid as much as it can
having dependencies of any kind :).

Moty
 
A

Allan Ebdrup

Jon Skeet said:
But how long does fetching the data take anyway, and how much
concurrency do you expect? If it's quick, it could well be that using
a ReaderWriter lock is still more expensive than a plain exclusive
monitor lock.

In one case fetching the data and updating the data (writer lock) takes
several minutes
Reading the data is called from many threads and the readlock is held for
several seconds on each thread.
It would be a nice idea if it were feasible - but I don't *think* it
is.

Don't be so pessimistic, almost anything is possible.
I don't think it could upgrade an existing, held lock into a reader/
writer lock. With *very* carefully defined semantics it might be
possible to work something out, but I'm not entirely sure. I don't
think it's worth the extra work though, personally.

That's why I want MS to do the work ;-), it only has to be done once.

Kind Regards,
Allan Ebdrup
 
J

Jon Skeet [C# MVP]

In one case fetching the data and updating the data (writer lock) takes
several minutes
Reading the data is called from many threads and the readlock is held for
several seconds on each thread.

Right. I'd say that's a fairly unusual situation - I rarely need to
hold locks for that long.
Don't be so pessimistic, almost anything is possible.

Not within C# itself. If there were a CLR change as well, it might be
possible. That's clearly a much bigger task though, and I don't think
it's worth the effort.
That's why I want MS to do the work ;-), it only has to be done once.

I think there are other features I'd be much more interested in MS
working on, to be honest.

Jon
 
A

Allan Ebdrup

Moty Michaely said:
I would say that the language should try to avoid as much as it can
having dependencies of any kind :).

I agree that adding the feature to the language was a bad idea.
But I still like the idea of it beeing possible to upgrade a lock from a
monitor to a ReaderWriterLock if needed.
I guess I don't see why more work wasn't put into having those two locking
mechanisms behave more simular, seems to me that a ReaderWriterLock might as
well work on an object like a Monitor and might as well have Pulse so they
are more simular. Maybe I'm missing something but would Pulse on a
ReaderWriterLock not make sense? And would a ReaderWriterLock that works on
an object like Monitor not make sense?

Kind Regards,
Allan Ebdrup
 
M

Mark Rae

I think there are other features I'd be much more interested in MS
working on, to be honest.

You could always suggest it to Anders next time you do lunch... ;-)
 
D

Dave

Jon Skeet said:
It would be a nice idea if it were feasible - but I don't *think* it
is.

Well differentiating between a normal lock and a read/write lock could be
arranged easily enough. Something like lock(obj), readLock(obj),
writeLock(obj). Read and write locks could only be done on a custom
'ReadWriteLock' class. The code itself for a (albeit very VERY basic)
read/wrtie lock would just be a counter incremented for each reader
currently locking.
 
J

Jon Skeet [C# MVP]

Dave said:
Well differentiating between a normal lock and a read/write lock could be
arranged easily enough. Something like lock(obj), readLock(obj),
writeLock(obj). Read and write locks could only be done on a custom
'ReadWriteLock' class. The code itself for a (albeit very VERY basic)
read/wrtie lock would just be a counter incremented for each reader
currently locking.

But Allan's suggestion requires "upgrading" from a cheap mutex lock to
a reader/writer lock - and that's the tricky bit, IMO.
 
C

Chris Mullins [MVP]

Jon Skeet said:
I can't remember the last time I used one, and I've done plenty of
multi-threaded code.

At the other end of the spectrum, I use ReaderWriter locks quite a bit.

Our stuff runs on alot of multi-core and multi-processor machines, and we
actually end up with alot of lock contention as a result. I believe in most
multi-threaded apps, true lock contention is actually pretty rare and
locking is more for preventing corner cases and race conditions - so
Monitors work very well.

When I ran the profiler on an 16 processor (64GB of Memory) IA64 box, it
quickly became apparent that Monitor's were not going to cut it any longer.
We then switched our key datastructures over to use ReaderWriterLocks, and
things improved dramatically.

One of my frustrations here is the lack of a good overall solution. When I
was doing this profiling, I tried 3 solutions for locking around our various
stacks and queues:
Solution 1 - Monitors
Solution 2 - ReaderWriterLocks
Solution 3 - Lock Free Code

On a small box (1 or 2 processors) we saw:
- Monitors were clearly the best.
- ReaderWriterLocks were ok.
- Lock Free Stuff was slowest.

On meduim boxes (4 or 8 processors) we saw:
- Monitors were ok.
- ReaderWriterLocks were better.
- Lock Free Stuff was somewhere in between.

On big boxes (16 processors) we saw:
- Monitors Sucked
- ReaderWriterLock was ok.
- Lock Free was awesome.

(These results were across a mixture of x86, x64 and IA64 machines. I really
wish I had been more methodical in recording my results, as it would have
made a great blog entry....)

These results were very tied to our use cases - adding (and removing) data
to a queue for processing, checking for cache hits, expiring a cache,
updating a chache, and some other related cases.

There were 4 or 5 spots that really stood out as "Contention here!", and
this is where changing the lock structures made a difference. For the vast
majority of the locking we do, Monitors are the solution.

I've always wanted to "Write a smart locking class, that checks the
processor count at runtime, then uses the right lock & datastructure."
 
C

Chris Mullins [MVP]

I should mention the scales I'm talking about as well - if you're dealing
with small scale applications, everything I'm talking about is a waste of
time and you should just use whatever locking mechanism you and your team
understand the best (typically Monitors).

In the tests I described in the last post, we had 250,000 TCP connections
coming into a single server, with each connection actively sending and
receiving traffic.

This traffic is XMPP traffic, which means UTF-8 to UTF-16 encoding changes,
Xml Stanza ReAssembly (due to receive chunking), Xml Processing, Z-Lib
Compression, TLS Encryption, and a boatload of processing (Are my friends
online? Send me their status. Is anyone registred to be looking for me? Send
them my status. Do I have any offline messages pending? Send 'em over. Do I
have any offline events pending? Send them too. Gimme all my friends
Avatar's [even if they're offline, it should still be the newest avatar they
published], etc.)

I'm really looking forward to the networking improvements that Orcas brings.
The new Overlapped datastructures alone should give us a 50%+ boost in
scalability on comparable hardware....
 
J

Jon Skeet [C# MVP]

Chris Mullins said:
At the other end of the spectrum, I use ReaderWriter locks quite a bit.

Our stuff runs on alot of multi-core and multi-processor machines, and we
actually end up with alot of lock contention as a result. I believe in most
multi-threaded apps, true lock contention is actually pretty rare and
locking is more for preventing corner cases and race conditions - so
Monitors work very well.

When I ran the profiler on an 16 processor (64GB of Memory) IA64 box, it
quickly became apparent that Monitor's were not going to cut it any longer.
We then switched our key datastructures over to use ReaderWriterLocks, and
things improved dramatically.

Are you hoping to move to .NET 3.5 any time soon? I'd expect that with
the "slim" reader/writer lock, it should get better again.

Interesting reading about your experiences with other solutions - not
entirely surprising, but annoying, as you say...
 
C

Chris Mullins [MVP]

I hope so, but it's really up in the air at this point.

The problem is that our Client and Server are both built on top of the same
SDK - and that SDK needs to be able to run anywhere .Net 2.0 is installed.
The SDK is what sits on top of the sockets, reads the Xml, and turns Xml
Stanzas into instances of .Net classes. This needs to keep running on top of
the .Net 2.0 CLR, as that's installed in a lot of spots.

For the "server" portions of the codebase (the stuff that sits on top of the
SDK), switching to .Net 3.5 will happen as soon as Orcas goes live. The
networking improvements alone will justity it. I'm really hoping we can
continue to use the same code base, and see the improvements. Ideally the
same 2.0 assemblies, when run in the 3.5 CLR, will get the networking
improvements (specifically, the improvements to the Overlapped
datastructures, which is what really hobbled us last time).

I also want to go the route Richter went in his Power Threading library -
he's got an abstraction layer for his locks, so it's really easy to switch
out the lock types, with ReaderWriterLockSlim being one of the first things
to try.
 

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