Interlocked.Increment bug?

R

Ryan Liu

Hi,

Is there any known bug related to
Interlocked.Increment(ref var)?

My client report var's value going up and down in the client/server
multile-thread application. There are about 80 clients connect to one server
though TCP client.

But actully I never decrease var.

I change its type to volatile int and use lock to increase its value

lock(this.currentCountLock)
{
this.currentCount ++;
}
and handle over to my client. (It never decreases in my machine)


Thanks,
Ryan

BTW, why volatile can not be used with ref?
 
L

Lucian Wischik

Ryan Liu said:
Is there any known bug related to
Interlocked.Increment(ref var)?
My client report var's value going up and down in the client/server
multile-thread application. There are about 80 clients connect to one server
though TCP client.

You'll have to give us a bit more context. For instance, this code:

int ptr=0;

[thread1]
int x = Interlocked.Increment(ref ptr);
Console.WriteLine(x);

[thread2]
int y = Interlocked.Increment(ref ptr);
Console.WriteLine(y);

can quite happily print "2,1", which looks as if it's decrementing,
even though in reality it isn't and the code is working fine.


Also, are you using the Int64 version or the Int32 version? I know
there's a recently-discovered bug in the Int64 version of
Interlocked.Add. It's conceivable that Interlocked.Increment(Int64)
might have the same bug?
 
B

Brian Gideon

Ryan said:
BTW, why volatile can not be used with ref?

Ryan,

Because the receiving method would not be aware of the volatile
semantics. Also, if you're always using a lock then there's no need to
mark the field as volatile.

Brian
 
W

Willy Denoyette [MVP]

| >Is there any known bug related to
| >Interlocked.Increment(ref var)?
| >My client report var's value going up and down in the client/server
| >multile-thread application. There are about 80 clients connect to one
server
| >though TCP client.
|
| You'll have to give us a bit more context. For instance, this code:
|
| int ptr=0;
|
| [thread1]
| int x = Interlocked.Increment(ref ptr);
| Console.WriteLine(x);
|
| [thread2]
| int y = Interlocked.Increment(ref ptr);
| Console.WriteLine(y);
|
| can quite happily print "2,1", which looks as if it's decrementing,
| even though in reality it isn't and the code is working fine.
|
|
| Also, are you using the Int64 version or the Int32 version? I know
| there's a recently-discovered bug in the Int64 version of
| Interlocked.Add. It's conceivable that Interlocked.Increment(Int64)
| might have the same bug?
|
| --
| Lucian

How can it decrement when you are calling two times Interlocked.Increment,
I'm I missing something here?

Willy.
 
W

Willy Denoyette [MVP]

|
| || >Is there any known bug related to
|| >Interlocked.Increment(ref var)?
|| >My client report var's value going up and down in the client/server
|| >multile-thread application. There are about 80 clients connect to one
| server
|| >though TCP client.
||
|| You'll have to give us a bit more context. For instance, this code:
||
|| int ptr=0;
||
|| [thread1]
|| int x = Interlocked.Increment(ref ptr);
|| Console.WriteLine(x);
||
|| [thread2]
|| int y = Interlocked.Increment(ref ptr);
|| Console.WriteLine(y);
||
|| can quite happily print "2,1", which looks as if it's decrementing,
|| even though in reality it isn't and the code is working fine.
||
||
|| Also, are you using the Int64 version or the Int32 version? I know
|| there's a recently-discovered bug in the Int64 version of
|| Interlocked.Add. It's conceivable that Interlocked.Increment(Int64)
|| might have the same bug?
||
|| --
|| Lucian
|
| How can it decrement when you are calling two times Interlocked.Increment,
| I'm I missing something here?
|
| Willy.
|
|

Sorry forget my previous post, I misread the OP's question.

Willy.
 
M

Marc Gravell

No - it doesn't decrement, but it can *look* like it does, depending
on which thread runs hotter.

e.g.
* thread 1 increments and receives 1, and is then paused by the
scheduler
* thread 2 increments and receives 2
* thread 2 writes "2" to the console
* thread 1 wakes up and writes "1" to the console

it never decreases... just threading...

Of course, if you increment it enough times to overlflow int.MaxValue,
then that is different ;-p

Marc
 
W

William Stacey [C# MVP]

I am not following that. You seem to be mixing locks and interlocked. Can
we see a better sample of what your talking about.

--
William Stacey [C# MVP]

| Hi,
|
| Is there any known bug related to
| Interlocked.Increment(ref var)?
|
| My client report var's value going up and down in the client/server
| multile-thread application. There are about 80 clients connect to one
server
| though TCP client.
|
| But actully I never decrease var.
|
| I change its type to volatile int and use lock to increase its value
|
| lock(this.currentCountLock)
| {
| this.currentCount ++;
| }
| and handle over to my client. (It never decreases in my machine)
|
|
| Thanks,
| Ryan
|
| BTW, why volatile can not be used with ref?
|
|
 
R

Ryan Liu

Thanks, Brain!

Then:

if the volatile variable is only be modified by var++ , then no need to use
lock to prevent it from not increasing value?

if variable can be modified by hardware, then volatile is still needed?

Thanks,
Ryan
 
R

Ryan Liu

Hi William,

Yes, I thought Interlocked does implicit lock or it doesn't really useful,
especially the variable is only simply advance itself.

I have abstract code following. I have a brife explain here first.

It is a client/Server application. There are 3 roles runs on differant
machines: Worker, Manager, and ApplicationServer.

Each worker works on a Item at a time.
When worker done a Item, it notifies server, and server advances the
project's current count if it is a "success" Item.

Each worker owns a thread in ApplicationServer, AppServer
talks(listen/write) to worker though that thread.

ApplicatonServer also have another backend thread run on an interval base to
read projects current value and update Managers. It check an arraylist to
see what projects need update. The project id is added to this arraylist
when worker's thread change current count in appServer.

Actual application is much more complicated then this. The following is
original code, and I am changing code to the one in comments.



public class Project
{

....

//later add this: private readonly object currentCountLock = new object();
private int currentCount; //later add volatile


public int CurrentCount
{
get
{
return this.currentCount;
}

}

/// <summary>
/// advance current by 1, in a atomic mode
/// </summary>
private void AdvanceCurrentCount()
{

Interlocked.Increment(ref this.currentCount);
//lock(this.currentCountLock)
//{
//this.currentCount ++;
//}

this.CheckIfFullAndMarkPPIfSo();
}

//80 workers' thread call this when it receive notificaton from workers
public bool DoneAnItem( ...)
{
...
if(successEnd)
{
AdvanceCurrentCount();
}
server.InfoClientQuotaChange(this);
}
}


public class Server
{

private ArrayList statusChangedProjects= new ArrayList();

// register status changed project id in the ArrayList
// then there is another thread scan this ArrayList
// to find out which project status
internal void InfoClientQuotaChange(Project project)
{
lock(this.statusChangedProjects.SyncRoot)
{
this.statusChangedProjects.Add(project.projectId);
}
}


.........
//backend thread
while(true)
{
foreach(Project p in statusChangedProjects)
{

sb.Append(p.CurrentCount);

}

//send sb.ToString() to manager

Thead.Sleep(500);

}
}

Thanks,
Ryan


William Stacey said:
I am not following that. You seem to be mixing locks and interlocked. Can
we see a better sample of what your talking about.

--
William Stacey [C# MVP]

| Hi,
|
| Is there any known bug related to
| Interlocked.Increment(ref var)?
|
| My client report var's value going up and down in the client/server
| multile-thread application. There are about 80 clients connect to one
server
| though TCP client.
|
| But actully I never decrease var.
|
| I change its type to volatile int and use lock to increase its value
|
| lock(this.currentCountLock)
| {
| this.currentCount ++;
| }
| and handle over to my client. (It never decreases in my machine)
|
|
| Thanks,
| Ryan
|
| BTW, why volatile can not be used with ref?
|
|
 
R

Ryan Liu

Thanks, everyone. I guess you guys are rignt, " looks as if it's
decrementing" is what happening.

I thought Interlocked does implicit lock or it doesn't really useful,
especially the variable is only simply advance itself.


And, Lucian, I am using Int32 version.

Ryan
 
R

Ryan Liu

Oh, on the second thought, I think that is not the case.

As said in another email in this conversation thread,
I have many threads advance the var,
and another single thread read it and show to the end user.

Then this "read" thead should never "looks as if it is decrementing" ...
 
B

Brian Gideon

Ryan said:
Thanks, Brain!

Then:

if the volatile variable is only be modified by var++ , then no need to use
lock to prevent it from not increasing value?

You still need to aquire a lock or use an interlocked operation. The
volatile keyword does not make any guarentees about atomicity. It has
more to do with when reads and writes of the variable occur.
if variable can be modified by hardware, then volatile is still needed?

Not necessarily. Any mechanism that produces a memory barrier should
be sufficient. Read the following article for more details.

http://www.yoda.arachsys.com/csharp/threads/volatility.shtml

Brian
 
J

Jon Skeet [C# MVP]

Ryan Liu said:
Then:

if the volatile variable is only be modified by var++ , then no need to use
lock to prevent it from not increasing value?

No - you still need a lock. Think of var++ as

var = var + 1;

Another thread could change the value of var between "var + 1" being
evaluated and "var" being assigned.
if variable can be modified by hardware, then volatile is still needed?

I'm not even sure if this is possible within managed code. Could you
give an example?
 
J

Jon Skeet [C# MVP]

Ryan Liu said:
Yes, I thought Interlocked does implicit lock or it doesn't really useful,
especially the variable is only simply advance itself.

No - there's no lock involved. The point of Interlocked is to avoid
using a lock at all.
I have abstract code following. I have a brife explain here first.

<snip>

Unfortunately, abstract code is rarely detailed enough: with threading,
the devil is in the detail.

Personally, I'd ignore Interlocked and volatile as mechanisms and use
locks until you have evidence that the use of locks is a significant
performance hit. Getting it right with locks is non-trivial, but it's a
lot easier (IMO) than getting it right without locks.
 
R

Ryan Liu

Jon Skeet said:
No - you still need a lock. Think of var++ as

var = var + 1;

Another thread could change the value of var between "var + 1" being
evaluated and "var" being assigned.


I'm not even sure if this is possible within managed code. Could you
give an example?


Just a general question, I think you are right, it is impossible for
managed code.

Thanks!


 
J

Jon Skeet [C# MVP]

Just a general question, I think you are right, it is impossible for
managed code.

"Volatile" means different things in different memory models. It has a
well-defined meaning in C#/.NET, but that's not the same as in C, for
instance.
 

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