13

I have a System.Timers.Timer that increments a counter every 3 seconds. Another thread may also set this variable to any value under some conditions.

Tried to use Interlocked.Increment but it does not have an overload for UInt16. The next thing in mind is lock, but I am not really sure how to make thread-safe access (read/write/increment) to this variable.

Edited: the code originally used an int, but changed to UInt16 as suggested

private volatile System.UInt16 mCounter = 0;
private readonly object mCounterLock = new object();
public System.UInt16 Counter {
  get {
    lock (mCounterLock) {
      return mCounter;
    }
  }
  set {
    lock (mCounterLock) {
      mCounter = value;
    }
  }
}
private System.Timers.Timer mCounterTimer;

void mCounter_Elapsed(object sender, System.Timers.ElapsedEventArgs e) {
  lock (mCounterLock) {
    Counter++;
  }
}
jalf
  • 243,077
  • 51
  • 345
  • 550
fxam
  • 3,874
  • 1
  • 22
  • 32
  • 1
    @JesusRamos, but there's no Interlocked.Increment(Int16) – fxam Jan 02 '12 at 07:41
  • 1
    It'd be a lot easier if you told us what the requirements are, rather than telling us half of a solution. From looking at your original question and the edit, it looks like the question is **not** about either incrementing int or uint16, but about incrementing *some type* up to 65535 and then wrapping around. That may make it a lot easier to answer, if you don't instead talk about specifically incrementing an `int` or a `UInt16` and adding unnecessary constraints. – jalf Jan 02 '12 at 08:20
  • @jalf, please ignore my original question. My edit had all the requirements upon reading JesusRamos suggestion: 1) increment an UInt16 and wrap to 0. 2) another thread may set the UInt16 to any value at any time. So the question is how to increment this UInt16 in a thread-safe way without using Interlocked.Increment. Sorry but I think your edit has somehow broke the requirement. – fxam Jan 02 '12 at 08:46
  • 1
    @fxam: but it doesn't have to be an uint16, according to your original question. What if someone has a solution for you which uses another data type? In your original question it was not a *requirement* that the data type was a `uint16`. But now it is? How does that make sense? – jalf Jan 02 '12 at 09:54
  • And if you don't like my edit, feel free to revert it. – jalf Jan 02 '12 at 09:56
  • @jalf, the original question was that I only need 2 bytes from Int32. JesusRamos pointed out that it fits perfectly and overflow naturally in UInt16. Having said that, now I think you have a point there as well: what if someone else has a solution without using UInt16? – fxam Jan 02 '12 at 10:41
  • @fxam: that's my point exactly. Your problem was that of atomically incrementing an integer from 0 to 65535, after which, as I understand it, it should wrap around to 0. If you leave it at that, then you give answerers the most flexibility to come up with answers. If you add extra constraints like "and the type **must** be UInt16, then you might rule out answers that would otherwise be perfect. So only add that kind of constraints if you really need it. If a solution which relied on using, say, `Int16` or `Int32` instead would be unacceptable. – jalf Jan 02 '12 at 13:21

4 Answers4

8

Use a combination of Interlocked.CompareExchange and Interlocked.Increment wherein you assign 0 if the value reaches 65535

P.K
  • 18,587
  • 11
  • 45
  • 51
7

Just change your Int32 value to Int16 if you only need 2 bytes. Since Shai removed his answer here's some code

UInt16 myval = 0;
Object myvalLock = new Object();
....
lock (myvalLock) { myval++; }
Jesus Ramos
  • 22,940
  • 10
  • 58
  • 88
7

I would just use an UInt32 with Interlocked.Increment and cast it to UInt16 after every read access.

Ringding
  • 2,856
  • 17
  • 10
1
volatile int iNum = 0;
...


iActual = iNum;
do
{
   iExpected = iActual;
   iNext = (iExpected+1) & 0xFFFF;
   iActual = Interlocked.CompareExchange (ref iNum, iNext, iExpected);
} while (iExpected != iActual);
return iNext;

This makes the increment thread safe vs. other increments. But you mention also 'read', 'write' and 'reset' and is impossible to tell, in context, if those operations are safe and even if the increment is dafe vs. said 'write' and specially 'reset' operations. Normally for such type of shared counters the only operation allowed is to increment it.

Remus Rusanu
  • 288,378
  • 40
  • 442
  • 569