c# - Interlocked.Exchange and value types

G

Guest

// What I want to do

Use enumerated types with the Interlocked.Exchange methods
Suggestions please

// My estimation of problem

Seems like Interlocked.Exchange only works with ints, referencable objects,
and floats

// Background

I have a class that wraps up a worker thread to handle various requests
The thread function is implemeted as a looped switch based state machine
The state machine states are enumerated (via an enum)
Requests are made by the client through various methods exposed by the class
Requests are embodied using the enumeration described above
The requested enum state variable gets filed away via interlocked exchange
for later retrieval by worker thread..

// Confessions

works fine with C++ and CRTL. I'm a C# newbie

cheers
 
G

Guest

I have a workaround that surprises me a little (well it compiles at least)

The c# compiler does not appear to complain about casts from enums to
integer types (btw this behaviour is different to C and C++).. So I can cast
from my c# enum to an int and back again using the int overload for
Interlocked.Exchange.

I'm guessing that I'll get a runtime exception if I try to cast an integer
value to an enum type that is out of range of the enum.. will try.

Anyway, if it works I'm happy. Comments??
 
J

Jon Skeet [C# MVP]

steve said:
I have a workaround that surprises me a little (well it compiles at least)

The c# compiler does not appear to complain about casts from enums to
integer types (btw this behaviour is different to C and C++).. So I can cast
from my c# enum to an int and back again using the int overload for
Interlocked.Exchange.

I'm guessing that I'll get a runtime exception if I try to cast an integer
value to an enum type that is out of range of the enum.. will try.

No, you won't. Enums aren't strict on that front.
Anyway, if it works I'm happy. Comments??

Sure - why not just use a volatile variable or locking? I know there's
a theoretical performance hit, but for most applications it's just that
- theoretical.

I would only consider using the Interlocked class if I absolutely knew
that the use of a volatile variable or a lock was a real performance
bottleneck.
 
G

Guest

Hi steve,

The Interlocked.Exchange Method has three overloaded versions:

1. public static int Exchange(ref int, int);
2. public static object Exchange(ref object, object);
3. public static float Exchange(ref float, float);

Since you are using an enum which does not fit to any of them, you need to
cast it to appropriate value before passing it as parameter.

Try the following code and it will work:

<CODE>
object someType3 = (object) someType1;
someType2 = (MyEnumType)Interlocked.Exchange(ref someType3,
(object)someType2);
someType1 = (MyEnumType)someType3;
</CODE>

But i guess it will defeat the purpose of using Interlocked.Exchange as this
operation will no more be an *Atomic* operation.

If you only want exclusive one thread operation you can use Monitor or Lock.
Check :

http://msdn.microsoft.com/library/d...tml/frlrfsystemthreadingmonitorclasstopic.asp
 
G

Guest

Thanks Jon,

The enum casts still have me curious. What does an out of range int map to
when cast as a enum?

If volatile in C# is the same as in C++, I'd have some concerns about using
it to define a state-control variable. volatile in C++ land means compiler
don't optimise.. I haven't read any doco that guarantees ops on volatile
variables wiull be atomic..

locking uses critical sections right. That's a pretty hefty price to pay
for a simple int type of exchange.. I think I'll pursue interlocks a bit
before throwing in the towl.

cheers

Steve
 
S

S. Senthil Kumar

How does volatile serve the purpose of Interlocked? I thought volatile
only guaranteed that changes to a variable by one thread will be
immediately visible to all other threads using the variable.
 
G

Guest

You don't need to do the conversions as a seperate step. You can use boxing
to pass the enum variable directly into the Interlocked calls.

// Support a three state control of a worker thread
enum RunState { Continue, Stop, Pause}

// We will use runState to send signals to the worker thread
object runState = RunState.Continue;

// In the worker thread, wait for the run state to change
while (!Interlocked.Equals(runState,RunState.Stop))

// In the main thread, signal the worker thread to stop
Interlocked.Exchange(ref runState,(object)RunState.Stop);
 
J

Jon Skeet [C# MVP]

steve said:
The enum casts still have me curious. What does an out of range int map to
when cast as a enum?

An enum with the value given. Sometimes it's useful to have enum values
outside the anticipated range (eg for HTTP status codes, where it's
fine for a web server to give a status code which can be understood by
a suitable client, but which may not have an official name) and
sometimes it's a pain.
If volatile in C# is the same as in C++, I'd have some concerns about using
it to define a state-control variable. volatile in C++ land means compiler
don't optimise.. I haven't read any doco that guarantees ops on volatile
variables wiull be atomic..

There's much more to this than atomicity - and volatility is taken into
account by the CLR, not just the initial compiler. It's a mistake to
make assumptions about .NET threading based on C++ idioms.

See http://www.pobox.com/~skeet/csharp/threads/volatility.shtml for
more information.
locking uses critical sections right. That's a pretty hefty price to pay
for a simple int type of exchange.. I think I'll pursue interlocks a bit
before throwing in the towl.

Locking uses the equivalent of critical sections, but they're very
cheap when they're uncontested in the CLR.
 
J

Jon Skeet [C# MVP]

S. Senthil Kumar said:
How does volatile serve the purpose of Interlocked? I thought volatile
only guaranteed that changes to a variable by one thread will be
immediately visible to all other threads using the variable.

Indeed. Sometimes that's enough, and sometimes it's not. Personally I
prefer to use locks in the first place...
 
G

Guest

Thanks Jon, I'll check out your link

Jon Skeet said:
An enum with the value given. Sometimes it's useful to have enum values
outside the anticipated range (eg for HTTP status codes, where it's
fine for a web server to give a status code which can be understood by
a suitable client, but which may not have an official name) and
sometimes it's a pain.


There's much more to this than atomicity - and volatility is taken into
account by the CLR, not just the initial compiler. It's a mistake to
make assumptions about .NET threading based on C++ idioms.

See http://www.pobox.com/~skeet/csharp/threads/volatility.shtml for
more information.


Locking uses the equivalent of critical sections, but they're very
cheap when they're uncontested in the CLR.
 
G

Guest

Thanks

What's the rough overhead of boxing? cheaper than using critical sections
aka locks?

Steve
 
J

Jon Skeet [C# MVP]

steve said:
What's the rough overhead of boxing? cheaper than using critical sections
aka locks?

Well, it's a different kind of cost - it costs "later on" when it comes
to garbage collection, as it's creating an extra object on the heap.
However, if you're boxing to temporary values, you lose the atomic
nature of the Interlocked operation.
 
G

Guest

Gooooood question...

Boxing is known to have a performance hit, as Jon mentions. I thought that
it didn't matter in my code because the boxing is performed in the
Interlocked.Exchange, to stop the thread, which is not frequently called,
however on a second look, I see that the Interlocked.Equals is also boxing
the RunState.Stop, and is being called very frequently. I'll have to leave it
here for the moment, and have a closer look. I think that declaring the
RunState.Stop as a constant object, and passing to Interlocked.Equals will
probably address the performance issue.

wrt. Jon's comment that the boxing loses the atomic nature of the
Interlocked operation, I think that this is not correct, as the essential
thing is that the subject variable is read from, and assigned to, atomically.
It doesn't matter if there is come complexity in computing the parameters to
the operation (ie. the complexity of boxing). But, I will also look at this a
bit later, and get back to you.
 
S

S. Senthil Kumar

Off topic, but why would you want to use the Interlocked.XXX methods
for comparing and assigning enum values? Declaring the variable as
volatile should do the job, if I read the docs correctly. The CLR
guarantees that any operation on type with size less than native ints,
is atomic, so why would you want to do Intelocked.Equals and Exchange?

Regards
Senthil
 
S

S. Senthil Kumar

Assuming you're using Interlocked.Add, there would be three steps
involved
Box the int value to an object
Atomically increment and assign the new value.
Unbox the object back to an int.

I think what Jon is saying is, the above 3 operations are not
guaranteed to be atomic.
 
J

Jon Skeet [C# MVP]

Javaman59 said:
wrt. Jon's comment that the boxing loses the atomic nature of the
Interlocked operation, I think that this is not correct, as the essential
thing is that the subject variable is read from, and assigned to, atomically.
It doesn't matter if there is come complexity in computing the parameters to
the operation (ie. the complexity of boxing). But, I will also look at this a
bit later, and get back to you.

You're absolutely right. I clearly wasn't thinking straight.
 
J

Jon Skeet [C# MVP]

S. Senthil Kumar said:
Assuming you're using Interlocked.Add, there would be three steps
involved
Box the int value to an object
Atomically increment and assign the new value.
Unbox the object back to an int.

I think what Jon is saying is, the above 3 operations are not
guaranteed to be atomic.

I wish that had been what I'd been trying to say :)

I was thinking about CompareExchange, but I was wrong about it. Because
the value that's being changed *to* doesn't rely on the previous value,
it's still atomic.
 
G

Guest

---------------------------------------------------------------------------------------

1. On the subject of boxing, and performance.

Original code:

// In the worker thread, wait for the run state to change
while (!Interlocked.Equals(runState,RunState.Stop)) // Yikes!!! Implicit
box of RunState.Stop, each time round the loop.VERY BAD!!

// In the main thread, signal the worker thread to stop
Interlocked.Exchange(ref runState,(object)RunState.Stop); // Box of
RunState.Stop is ok, because we won't call this frequently.

Solution:

// Move the boxing outside the loop, for efficiency
object stopState = (object) RunState.Stop
while (!Interlocked.Equals(runState,stopState))

Now it works sweetly!

The lesson from this..never, ever, use implicit boxing. ALWAYS make the box
explicit, so that any performance hit is visible.

eg. the first attempt should have read...

Interlocked.Equals(runState,(object)RunState.Stop)

---------------------------------------------------------------------------------------------

2. Should you use Interlocked? Is it safe with boxed variables?...

Yes, and Yes

From the help files...

The Interlocked methods CompareExchange, Decrement, Exchange, and Increment
provide a simple mechanism for synchronizing access to a variable that is
shared by multiple threads. The threads of different processes can use this
mechanism if the variable is in shared memory.

....

On modern processors, the methods of the Interlocked class can often be
implemented by a single instruction. Thus, the methods of the Interlocked
class provide very high-performance synchronization, and can be used to build
higher-level synchronization mechanisms, like spin locks.
 
G

Guest

Note, that "volatile" can be use only on entities which fit in 32 bits - the
reason is simple: assign operations on these entities are working as atomic
operations, so the "volatile" needs to solve only the ordering and cache sync
problems. Compare operation is also atomic, but if you need to chain it woth
some other operations - use lock.
Jiri
 
G

Guest

Off topic? I don't think so :) You make a good point.

I've used volatile in C++ programming, but I'm sticking with Interlocked in
c#, just because it means I can do both simple flag controls (such as this
enum example), and more complex counters (using Increment), with the one
mechanism. If I can avoid ever using volatile, then I will do so - not
because it's bad, but because it's yet another complication.
 

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