Jump to page: 1 26  
Page
Thread overview
[dmd-concurrency] draft 7
Feb 01, 2010
Michel Fortin
Feb 01, 2010
Robert Jacques
Feb 01, 2010
Robert Jacques
Feb 01, 2010
Michel Fortin
Feb 01, 2010
Michel Fortin
Feb 01, 2010
Michel Fortin
Feb 01, 2010
Robert Jacques
Feb 02, 2010
Robert Jacques
Feb 01, 2010
Michel Fortin
Feb 01, 2010
Michel Fortin
Feb 01, 2010
Michel Fortin
Feb 01, 2010
Extrawurst
Feb 01, 2010
Robert Jacques
Feb 01, 2010
Robert Jacques
Feb 01, 2010
Sean Kelly
Feb 01, 2010
Robert Jacques
Feb 01, 2010
Robert Jacques
Feb 01, 2010
Fawzi Mohamed
Feb 01, 2010
Fawzi Mohamed
Feb 01, 2010
Michel Fortin
Feb 01, 2010
Fawzi Mohamed
Feb 02, 2010
Michel Fortin
Feb 02, 2010
Fawzi Mohamed
Feb 02, 2010
Fawzi Mohamed
Feb 02, 2010
Fawzi Mohamed
Feb 02, 2010
Fawzi Mohamed
Feb 02, 2010
Sean Kelly
Feb 02, 2010
Robert Jacques
Feb 02, 2010
Fawzi Mohamed
Feb 02, 2010
Fawzi Mohamed
Feb 02, 2010
Sean Kelly
Feb 02, 2010
Fawzi Mohamed
Feb 02, 2010
Sean Kelly
Feb 02, 2010
Sean Kelly
Feb 02, 2010
Sean Kelly
Feb 02, 2010
Fawzi Mohamed
Feb 02, 2010
Fawzi Mohamed
Feb 02, 2010
Sean Kelly
Feb 02, 2010
Fawzi Mohamed
Feb 02, 2010
Sean Kelly
Feb 02, 2010
Fawzi Mohamed
February 01, 2010
I've entered "synchronized" full speed, but haven't finished (e.g. synchronized constructors aren't yet discussed). New stuff starts around page 21. Please give this a very close read. Thanks.

http://erdani.com/d/fragment.preview.pdf

Walter, you may want to make sure we're on the same page with everything.


Andrei
February 01, 2010
Quote from draft 7:

> Anyway, real is meant mostly for high-precision temporary results and not for data interchange, so it makes little sense to want to share it anyway.

Are you sure? Real is perfect for *inter-thread* data interchange. If you're splitting a long computation between different threads, why would you want to cut precision when communicating back the result?

> auto lock = Lock(_guard);

Shouldn't you mention it's a C++ idiom?

> The program would compile successfully with the following changes to nyukNyuk and sneaky:
> 
> shared(double)* nyukNyuk; // or: shared(double*) nyukNyuk;
> void sneaky(ref shared(double) r) { nyukNyuk = &r; }

How can that be safe? Leaking the reference, even as 'shared', doesn't prevent someone from accessing the variable without acquiring the lock. Are you suggesting that mixing atomic operations and mutex synchronization for the same variable is okay? Because it's not.

-- 
Michel Fortin
michel.fortin at michelf.com
http://michelf.com/



February 01, 2010
Hum, say I want to implement a synchronized Bank class as a collection of bank accounts:

	synchronized class Bank {
		private BankAccount[name] accounts;
		private string[] log;

		void addAccount(string name) {
			accounts[name] = new BankAccount();
			log ~= "account created";
		}

		void transferMoney(string from, string to, uint amount) {
			BankAccount first = accounts[from];
			BankAccount second = accounts[to];
			synchronized (first, second) {
				first.withdraw(amount);
				second.deposit(amount);
				log ~= "money transfer successful";
			}
		}

		void removeAccount(string name) {
			accounts.remove(name);
			log ~= "account removed";
		}
	}

Where am I going to need casts here?
Also, which parts are going to be done using atomic operations?

-- 
Michel Fortin
michel.fortin at michelf.com
http://michelf.com/



February 01, 2010
Hi Andrei,

I like it more and more with every draft.

Some parts need to be corrected in my opinion:


1.11 (p.21) "Such a variable is visible to all threads in the system" Isn't it just visible to the threads of the process ?

1.12 (p.24) "[..] real, which is the only a platform dependent type" the "a" sounds wrong ;)

1.13 (p.28) the balance() method lacks the "@property"

1.14.2 (p.30) "Inside a method of BankAccount, _parent must be [..]" According to the corresponding code above the quote the member is called _issuer instead of _parent

1.14 (p.31) the balance() method lacks the "@property"

1.15 (p.33) the balance() method lacks the "@property"



Keep up the good work.

Regards,
Stephan Dilly



On 01.02.2010 13:07, Andrei Alexandrescu wrote:
> I've entered "synchronized" full speed, but haven't finished (e.g. synchronized constructors aren't yet discussed). New stuff starts around page 21. Please give this a very close read. Thanks.
>
> http://erdani.com/d/fragment.preview.pdf
>
> Walter, you may want to make sure we're on the same page with everything.
>
>
> Andrei
> _______________________________________________
> dmd-concurrency mailing list
> dmd-concurrency at puremagic.com
> http://lists.puremagic.com/mailman/listinfo/dmd-concurrency
>
February 01, 2010
Page 24, P1: "The notable absent is real, which is the only a platform
dependent type that the implementation has discretion regarding atomic
sharing."
which is the only a platform dependent type => which is a platform
dependent type

Page 28, P3: "good ole days of classic multithreading;"
ole => old

Page 28 Comments:
The limitations on internal data should be mentioned.
- Can private members be accessed by other functions/etc inside
BankAccount's module
- Do member have to be private? Can they be protected? Public?
- Would a transfer function like this be possible?
   synchronized class BankAccount {
     private double _balance;
     void transfer(BankAccount dst, double amount) {
       enforce(_balance >= amount);
       _balance     -= amount;
       dst._balance += amount;
     }
   }
   or would you have to do it like the later example?
- Are arrays and associative arrays supported?

Section 1.14.1 Comments:
If a reference to data protected by synchronization escapes, then races
can and will occur. This seems like a fundamental flaw in the design. I
think a cast should be required to enable an escape.

Page 30 Last P: "Inside a method of BankAccount, _parent must be considered of type shared(BankAccount).": Did you mean _issuer and Bank?

Page 32 P2: "It is not impossible the issue might be revisited later": impossible the => impossible and the

February 01, 2010
I just have time for a quick reading, but here are a few comments:

1.5 uses tid.send() while 1.6 uses send(tid) with no explanation as to why.  Perhaps send(tid) should be used throughout, with tid.send() optionally introduced later after shared UDTs are discussed.

Time values in Druntime use a resolution of 100 nanoseconds (same as C#).  We should probably expose the same for messaging.  In truth, we really need a TimeSpan struct to simplify things, since expressing time intervals using numeric literals is horribly error-prone.

I must say I still kind of like having a timeout handler within receive:

receive( (int x) {},
                (string y) {},
                timeout(1000, { writeln("timed out"); } );

but I guess both could really be offered with receiveTimeout as a wrapper around receive, similar to receiveOnly.

The code snippet for 1.6.1 spans 2 pages.  Necessary, I suppose, but I've never liked when that happens.

1.10 - If I change the size of a mailbox to be less than the number of messages currently in the mailbox, what happens?

1.11 Why atomicOp!"+="(x, 1) instead of atomic(x) += 1?

1.12 "The notable absent is real" -> "The notable absence is real" or perhaps "real is notably absent"

1.12.1 There should be some mention about whether unshared operations can be optimized across shared operations.  This is basically the Java memory model for volatile, so it may be worth looking at how that's explained or simply mentioning this as well.

1.13 "scope(exit) _guard.unlock();" would work as well.

1.14.1 I assume you mean that if the address of a field escapes, all accesses of that field must be atomic?  You can't mix atomic and non-atomic accesses to a variable.  I like that you've tried to use the type system to simplify things here, but this seems like a potential problem.

1.14.2 What is _parent?

1.15 Multi-argument synchronized() is cool.
February 01, 2010
(I assume you meant "BankAccount[string]".)

It all depends on the behavior of the types shared(BankAccount[string]), shared(BankAccount), and shared(string[]).

I didn't quite mention what happens to member arrays inside synchronized methods. I think I wouldn't have to, but ~= warrants it. Here's the deal: inside a synchronized method, a member of type T[] is shared(T)[], except if you want to take the address of the member, in which case it's shared(T[]). Yep, that's tail const. I haven't thought a great deal about this, but arrays of shared(T) may be appended to efficiently.

I have given zero thought to shared associative arrays, and this is a great time to start talking about it. For my money I think we need to have a whole separate type SharedMap(K, V).

Thanks for the question. Also thanks to Extrawurst and Sean for the feedback.


Andrei

Michel Fortin wrote:
> Hum, say I want to implement a synchronized Bank class as a collection of bank accounts:
> 
> 	synchronized class Bank {
> 		private BankAccount[name] accounts;
> 		private string[] log;
> 
> 		void addAccount(string name) {
> 			accounts[name] = new BankAccount();
> 			log ~= "account created";
> 		}
> 
> 		void transferMoney(string from, string to, uint amount) {
> 			BankAccount first = accounts[from];
> 			BankAccount second = accounts[to];
> 			synchronized (first, second) {
> 				first.withdraw(amount);
> 				second.deposit(amount);
> 				log ~= "money transfer successful";
> 			}
> 		}
> 
> 		void removeAccount(string name) {
> 			accounts.remove(name);
> 			log ~= "account removed";
> 		}
> 	}
> 
> Where am I going to need casts here?
> Also, which parts are going to be done using atomic operations?
> 
February 01, 2010
Page 24, P1: "The notable absent is real, which is the only a platform
dependent type that the implementation has discretion regarding atomic
sharing."
which is the only a platform dependent type => which is a platform
dependent type

Page 28, P3: "good ole days of classic multithreading;"
ole => old

Page 28 Comments:
The limitations on internal data should be mentioned.
- Can private members be accessed by other functions/etc inside
BankAccount's module
- Do member have to be private? Can they be protected? Public?
- Would a transfer function like this be possible?
     synchronized class BankAccount {
       private double _balance;
       void transfer(BankAccount dst, double amount) {
         enforce(_balance >= amount);
         _balance     -= amount;
         dst._balance += amount;
       }
     }
     or would you have to do it like the later example?
- Are arrays and associative arrays supported?

Section 1.14.1 Comments:
If a reference to data protected by synchronization escapes, then races
can and will occur. This seems like a fundamental flaw in the design. I
think a cast should be required to enable an escape.

Page 30 Last P: "Inside a method of BankAccount, _parent must be considered of type shared(BankAccount).": Did you mean _issuer and Bank?

Page 32 P2: "It is not impossible the issue might be revisited later": impossible the => impossible and the
February 01, 2010
Robert Jacques wrote:
> Page 24, P1: "The notable absent is real, which is the only a platform
> dependent type that the implementation has discretion regarding atomic
> sharing."
> which is the only a platform dependent type => which is a platform
> dependent type
> 
> Page 28, P3: "good ole days of classic multithreading;"
> ole => old

Isn't "good ole" an Americanism?

> Page 28 Comments:
> The limitations on internal data should be mentioned.
> - Can private members be accessed by other functions/etc inside
> BankAccount's module

No. I forgot to mention that. It's the one place where the compiler strenghtens private from module-level to class-level.

> - Do member have to be private? Can they be protected? Public?

Undecided.

> - Would a transfer function like this be possible?
>     synchronized class BankAccount {
>       private double _balance;
>       void transfer(BankAccount dst, double amount) {
>         enforce(_balance >= amount);
>         _balance     -= amount;
>         dst._balance += amount;
>       }
>     }
>     or would you have to do it like the later example?

Relaxation of field typechecking only happens for "this", not for other objects. If the above were allowed, it would only lock one object.

Now, say you use atomic add for dst. In that case, you can implement transfer as above. It would be a mild violation of encapsulation because you deposit without calling deposit().

> - Are arrays and associative arrays supported?

Arrays, yes. Associative arrays, I don't know.

> Section 1.14.1 Comments:
> If a reference to data protected by synchronization escapes, then races
> can and will occur. This seems like a fundamental flaw in the design. I
> think a cast should be required to enable an escape.

Low-level races won't occur because at most you escape references to shared values. No?

> Page 30 Last P: "Inside a method of BankAccount, _parent must be considered of type shared(BankAccount).": Did you mean _issuer and Bank?
> 
> Page 32 P2: "It is not impossible the issue might be revisited later": impossible the => impossible and the

I meant something like "it's not impossible that the issue" but probably I'll rephrase.


Thanks,

Andrei
February 01, 2010
Sorry for the duplicate post.
« First   ‹ Prev
1 2 3 4 5 6