February 01, 2010 [dmd-concurrency] draft 7 | ||||
---|---|---|---|---|
| ||||
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 [dmd-concurrency] draft 7 | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu | 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 [dmd-concurrency] draft 7 | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu | 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 [dmd-concurrency] draft 7 | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu | 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 [dmd-concurrency] draft 7 | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu | 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 [dmd-concurrency] draft 7 | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu | 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 [dmd-concurrency] draft 7 | ||||
---|---|---|---|---|
| ||||
Posted in reply to Michel Fortin | (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 [dmd-concurrency] draft 7 | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu | 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 [dmd-concurrency] draft 7 | ||||
---|---|---|---|---|
| ||||
Posted in reply to Robert Jacques | 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 [dmd-concurrency] draft 7 | ||||
---|---|---|---|---|
| ||||
Posted in reply to Robert Jacques | Sorry for the duplicate post. |
Copyright © 1999-2021 by the D Language Foundation