www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - atomicOp problem

reply Benjamin Thaut <code benjamin-thaut.de> writes:
I recently read the book "the D programming language" and wanted to try 
out a few of the multithreaded examples pointed out in this book. I 
tried to write a version of the bank account example using the atomicOp 
from core.atomic. But when I compile it, it never finishes, it just gets 
stuck in a endless loop inside atomic.d I think.
Here is the code:

import std.stdio;
import std.concurrency;

enum Messages {
	GO
}

shared class Account {
	private float amount = 0;
		
	float getAmount() const {
		return amount;
	}
		
	void change(float change){
		atomicOp!"+="(amount,change);
	}
}

shared Account bank = null;
	
void otherThread(Tid father){
	send(father,Messages.GO);
	for(int i=0;i<1000;i++)
		bank.change(-100);
}

void main(string[] args)
{
	bank = new Account();
	spawn(&otherThread,thisTid);
	receiveOnly!(Messages)();
	for(int i=0;i<1000;i++)
		bank.change(+100);
	writefln("Program finished. Amount is %s",bank.getAmount());
}

If you could please point out what I did wrong I would be very glad. If 
I did not do anything wrong, I don't quite understand whats the exact 
problem because the code inside atomic.d looks good (at least at my 
level of understanding)

-- 
Kind Regards
Benjamin Thaut
Oct 21 2010
next sibling parent "BCS" <anon anon.com> writes:
Benjamin Thaut <code benjamin-thaut.de> wrote:
 I recently read the book "the D programming language" and wanted to try 
 out a few of the multithreaded examples pointed out in this book. I 
 tried to write a version of the bank account example using the atomicOp 
 from core.atomic. But when I compile it, it never finishes, it just gets 
 stuck in a endless loop inside atomic.d I think.
[...]
 If you could please point out what I did wrong I would be very glad. If 
 I did not do anything wrong, I don't quite understand whats the exact 
 problem because the code inside atomic.d looks good (at least at my 
 level of understanding)
Are you sure it's endless? IIRC atomic increment on x86 has some fairly severe performance considerations and you are setting it ip for maximal contention. Try running it for 100 cycles and see if that works. OTOH I'm no expert so I could be totally off base.
 -- 
 Kind Regards
 Benjamin Thaut
Oct 21 2010
prev sibling parent Heywood Floyd <soul8o8 gmail.com> writes:
Interesting!
I get the same result, ie an infinite loop, with the CPU at 100%

Some things I noticed:
- Changing the for-loops to 100 or 10 doesn't help.
- Changing the atomicOp from "+=" to just "+" makes it work (although the
account doesn't get changed)
- Adding a Thread.sleep(1000) in one of the for-loops, before the call to
atomic-op, makes it all work with "+=" as well


By looking at the code in atomic.d it looks the "+="-operator ends up here:


            T get, set;            
            do
            {
                get = set = atomicLoad!(msync.raw)( val );
                mixin( "set " ~ op ~ " mod;" );
            } while( !cas( &val, get, set ) );
            return set;


And I suppose the cas()-function never returns true?

I don't know how atomic is supposed to work, so I'm not sure if it's a bug or
not. I'm no expert with D, or threading for that matter, so I don't know.  (I'm
just an expert guesser : ) 

I guess bug!


BR
/HF








Benjamin Thaut Wrote:

 I recently read the book "the D programming language" and wanted to try 
 out a few of the multithreaded examples pointed out in this book. I 
 tried to write a version of the bank account example using the atomicOp 
 from core.atomic. But when I compile it, it never finishes, it just gets 
 stuck in a endless loop inside atomic.d I think.
 Here is the code:
 
 import std.stdio;
 import std.concurrency;
 
 enum Messages {
 	GO
 }
 
 shared class Account {
 	private float amount = 0;
 		
 	float getAmount() const {
 		return amount;
 	}
 		
 	void change(float change){
 		atomicOp!"+="(amount,change);
 	}
 }
 
 shared Account bank = null;
 	
 void otherThread(Tid father){
 	send(father,Messages.GO);
 	for(int i=0;i<1000;i++)
 		bank.change(-100);
 }
 
 void main(string[] args)
 {
 	bank = new Account();
 	spawn(&otherThread,thisTid);
 	receiveOnly!(Messages)();
 	for(int i=0;i<1000;i++)
 		bank.change(+100);
 	writefln("Program finished. Amount is %s",bank.getAmount());
 }
 
 If you could please point out what I did wrong I would be very glad. If 
 I did not do anything wrong, I don't quite understand whats the exact 
 problem because the code inside atomic.d looks good (at least at my 
 level of understanding)
 
 -- 
 Kind Regards
 Benjamin Thaut
Oct 21 2010