all groups > c# > july 2005 >
You're in the c# group:
c# - Interlocked.Exchange and value types
c#:
// 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
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?? [quoted text, click to view] "steve" wrote: > // 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 >
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/default.asp?url=/library/en-us/cpref/html/frlrfsystemthreadingmonitorclasstopic.asp -- Cheers, Rahul Anand [quoted text, click to view] "steve" wrote: > 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?? > > "steve" wrote: > > > // 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 > >
[quoted text, click to view] S. Senthil Kumar <senthil.thecoder@gmail.com> wrote: > 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... -- Jon Skeet - <skeet@pobox.com> http://www.pobox.com/~skeet
[quoted text, click to view] steve <steve@discussions.microsoft.com> wrote: > 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. [quoted text, click to view] > 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. [quoted text, click to view] > 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. -- Jon Skeet - <skeet@pobox.com> http://www.pobox.com/~skeet
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 [quoted text, click to view] "Jon Skeet [C# MVP]" wrote: > steve <steve@discussions.microsoft.com> wrote: > > 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. > > -- > Jon Skeet - <skeet@pobox.com> > http://www.pobox.com/~skeet > If replying to the group, please do not mail me too
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.
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); [quoted text, click to view] "Rahul Anand" wrote: > 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/default.asp?url=/library/en-us/cpref/html/frlrfsystemthreadingmonitorclasstopic.asp > > -- > Cheers, > Rahul Anand > > "steve" wrote: > > > 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?? > > > > "steve" wrote: > > > > > // 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 > > >
[quoted text, click to view] steve <steve@discussions.microsoft.com> wrote: > 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. [quoted text, click to view] > 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. -- Jon Skeet - <skeet@pobox.com> http://www.pobox.com/~skeet
Thanks Jon, I'll check out your link [quoted text, click to view] "Jon Skeet [C# MVP]" wrote: > steve <steve@discussions.microsoft.com> wrote: > > 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. > > -- > Jon Skeet - <skeet@pobox.com> > http://www.pobox.com/~skeet > If replying to the group, please do not mail me too
Thanks What's the rough overhead of boxing? cheaper than using critical sections aka locks? Steve [quoted text, click to view] "Javaman59" wrote: > 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); > > > "Rahul Anand" wrote: > > > 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/default.asp?url=/library/en-us/cpref/html/frlrfsystemthreadingmonitorclasstopic.asp > > > > -- > > Cheers, > > Rahul Anand > > > > "steve" wrote: > > > > > 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?? > > > > > > "steve" wrote: > > > > > > > // 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 > > > >
[quoted text, click to view] Javaman59 <Javaman59@discussions.microsoft.com> wrote: > 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. -- Jon Skeet - <skeet@pobox.com> http://www.pobox.com/~skeet
[quoted text, click to view] S. Senthil Kumar <senthil.thecoder@gmail.com> wrote: > 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. -- Jon Skeet - <skeet@pobox.com> http://www.pobox.com/~skeet
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. [quoted text, click to view] "steve" wrote: > Thanks > > What's the rough overhead of boxing? cheaper than using critical sections > aka locks? > > Steve > > "Javaman59" wrote: > > > 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); > > > > > > "Rahul Anand" wrote: > > > > > 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/default.asp?url=/library/en-us/cpref/html/frlrfsystemthreadingmonitorclasstopic.asp > > > > > > -- > > > Cheers, > > > Rahul Anand > > > > > > "steve" wrote: > > > > > > > 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?? > > > > > > > > "steve" wrote: > > > > > > > > > // 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 > > > > >
[quoted text, click to view] steve <steve@discussions.microsoft.com> wrote: > 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. -- Jon Skeet - <skeet@pobox.com> http://www.pobox.com/~skeet
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
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.
--------------------------------------------------------------------------------------- 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.
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 [quoted text, click to view] "S. Senthil Kumar" wrote: > 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 >
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. [quoted text, click to view] "S. Senthil Kumar" wrote: > 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 >
Don't see what you're looking for? Try a search.
|
|
|