June 01, 2012 Re: synchronized (this[.classinfo]) in druntime and phobos | ||||
---|---|---|---|---|
| ||||
Posted in reply to deadalnix | On 06/01/12 14:26, deadalnix wrote: > Le 31/05/2012 20:17, Andrei Alexandrescu a écrit : >> On 5/31/12 5:19 AM, deadalnix wrote: >>> The solution consisting in passing a delegate as parameter or as template is superior, because it is now clear who is in charge of the synchronization, reducing greatly chances of deadlock. >> >> It can also be a lot clunkier for certain abstractions. Say I want a ProducerConsumerQueue. It's much more convenient to simply make it a synchronized class with the classic primitives, instead of primitives that accept delegates etc. >> >> Nevertheless I think there's merit in this idea. One thing to point out is that the idiom can easily be done today with a regular class holding a synchronized class private member. >> >> So we got everything we need. >> >> >> Andrei > > I was thinking about that. Here is what I ended up to think is the best solution : > > synchronized classes exists. By default, they can't be use as parameter for synchronized(something) . > > synchronized(something) will be valid is something provide opSynchronized(scope delegate void()) or something similar. Think opApply here. The synchronized statement is rewritten in a call to that delegate. This has similar issues as opApply. It would have to be a template and always inlined; The opLock/opUnlock approach lets you do the same things w/o the delegate overhead and signature restrictions while making it a bit harder to screw up the locking. > It open door for stuff like : > ReadWriteLock rw; > synchronized(rw.read) { > > } > > synchronized(rw.write) { > > } > > And many types of lock : spin lock, interprocesses locks, semaphores, . . . And all can be used with the synchronized syntax, and without exposing locking and unlocking primitives. > > What do people think ? It can already be done using 'synchronized', it's *only* an issue of efficiency and syntax. Eg right now i'm doing { scope s = somesemaphore.sync; whatever(); } and a properly lowered 'synchronized' would turn that into synchronized (somesemaphore) { whatever(); } Currently, the latter is probably possible, but not w/o a huge perf hit; the former is practically free, just as if it was written as: somesemaphore.wait(); try whatever(); finally somesemaphore.post(); Lowering 'synchronized' is about making the second form possible, for anything resembling some kind of synchronization primitive. OpSynchronized isn't necessary. artur |
June 01, 2012 Re: synchronized (this[.classinfo]) in druntime and phobos | ||||
---|---|---|---|---|
| ||||
Posted in reply to Steven Schveighoffer | Le 01/06/2012 14:52, Steven Schveighoffer a écrit :
> On Fri, 01 Jun 2012 08:38:45 -0400, Dmitry Olshansky
> <dmitry.olsh@gmail.com> wrote:
>
>> On 01.06.2012 16:26, deadalnix wrote:
>>> Here is what I ended up to think is the best
>>> solution :
>>>
>>> synchronized classes exists. By default, they can't be use as parameter
>>> for synchronized(something) .
>>>
>>> synchronized(something) will be valid is something provide
>>> opSynchronized(scope delegate void()) or something similar. Think
>>> opApply here. The synchronized statement is rewritten in a call to that
>>> delegate.
>>>
>>> Here are the benefit of such an approach :
>>> 1/ Lock and unlock are not exposed. You can only use them by pair.
>>> 2/ You cannot lock on any object, so you avoid most liquid locks and
>>> don't waste memory.
>>> 3/ synchronized classes ensure that a class can be shared and it
>>> internal are protected from concurrent access.
>>> 4/ It is not possible possible by default to lock on synchronized
>>> classes's instances. It grant better control over the lock and it is now
>>> clear which piece of code is responsible of it.
>>> 5/ The design allow the programmer to grant the permission to lock on
>>> synchronized classes's instances if he/she want to.
>>> 6/ It is now possible to synchronize on a broader range of user defined
>>> stuffs.
>>>
>>> The main drawback is the same as opApply : return (and break/continue
>>> but it is less relevant for opSynchronized). Solution to this problem
>>> have been proposed in the past using compiler and stack magic.
>>>
>>> It open door for stuff like :
>>> ReadWriteLock rw;
>>> synchronized(rw.read) {
>>>
>>> }
>>>
>>> synchronized(rw.write) {
>>>
>>> }
>>>
>>> And many types of lock : spin lock, interprocesses locks, semaphores, .
>>> . . And all can be used with the synchronized syntax, and without
>>> exposing locking and unlocking primitives.
>>>
>>> What do people think ?
>>
>> +1. Works for me.
>>
>> It refines what I believe the shadow cabinet (loosely: me, you, Alex,
>> Regan Heath and Steven) propose.
>
> Is this really necessary? When is opSynchronized going to be written any
> way other than:
>
> _mutex.lock();
> scope(exit) _mutex.unlock();
> dg();
>
> I'll note that it's easier to forget to lock or unlock if the compiler
> isn't enforcing it. You might even naively do this:
>
> _mutex.lock();
> dg();
> _mutex.unlock(); // not called on exception thrown!
>
> I kind of like the __lock() __unlock() pair that the compiler always
> calls both in the right place/way. Yes, you could just leave those
> implementations blank, but very unlikely.
>
> Plus, we already have issues with inout and delegates for opApply, this
> would have the same issues.
>
>> P.S. Removing monitor from non-synced/shared classes would be good
>> too. As a separate matter.
>
> I think at this point, we should leave it there until we can really
> figure out a detailed plan on how to deal with it. It currently affects
> all runtime code which does virtual function lookups or interface
> lookups, and alignment. We would have to change a lot of compiler and
> runtime code to remove it.
>
A lot of work have to be done, for sure. But concurency is the next big thing D will have to face IMO. When const/immutable are fixed :D
|
June 01, 2012 Re: synchronized (this[.classinfo]) in druntime and phobos | ||||
---|---|---|---|---|
| ||||
Posted in reply to deadalnix | On Jun 1, 2012, at 5:26 AM, deadalnix wrote: > > The main drawback is the same as opApply : return (and break/continue but it is less relevant for opSynchronized). Solution to this problem have been proposed in the past using compiler and stack magic. > > It open door for stuff like : > ReadWriteLock rw; > synchronized(rw.read) { > > } > > synchronized(rw.write) { > > } Opens the door? This works today exactly as outlined above. Or am I missing a part of your argument? > And many types of lock : spin lock, interprocesses locks, semaphores, . . . And all can be used with the synchronized syntax, and without exposing locking and unlocking primitives. All works today. |
June 03, 2012 Re: synchronized (this[.classinfo]) in druntime and phobos | ||||
---|---|---|---|---|
| ||||
Posted in reply to Sean Kelly | Le 01/06/2012 22:55, Sean Kelly a écrit :
> On Jun 1, 2012, at 5:26 AM, deadalnix wrote:
>>
>> The main drawback is the same as opApply : return (and break/continue but it is less relevant for opSynchronized). Solution to this problem have been proposed in the past using compiler and stack magic.
>>
>> It open door for stuff like :
>> ReadWriteLock rw;
>> synchronized(rw.read) {
>>
>> }
>>
>> synchronized(rw.write) {
>>
>> }
>
> Opens the door? This works today exactly as outlined above. Or am I missing a part of your argument?
>
>> And many types of lock : spin lock, interprocesses locks, semaphores, . . . And all can be used with the synchronized syntax, and without exposing locking and unlocking primitives.
>
> All works today.
Unless you do some monitor magic, it doesn't.
|
June 03, 2012 Re: synchronized (this[.classinfo]) in druntime and phobos | ||||
---|---|---|---|---|
| ||||
Posted in reply to deadalnix Attachments:
| On Sun, Jun 3, 2012 at 12:29 PM, deadalnix <deadalnix@gmail.com> wrote:
> Le 01/06/2012 22:55, Sean Kelly a écrit :
>
>> On Jun 1, 2012, at 5:26 AM, deadalnix wrote:
>>
>>>
>>> The main drawback is the same as opApply : return (and break/continue
>>> but it is less relevant for opSynchronized). Solution to this problem have
>>> been proposed in the past using compiler and stack magic.
>>>
>>> It open door for stuff like :
>>> ReadWriteLock rw;
>>> synchronized(rw.read) {
>>>
>>> }
>>>
>>> synchronized(rw.write) {
>>>
>>> }
>>>
>>
>> Opens the door? This works today exactly as outlined above. Or am I missing a part of your argument?
>>
>> And many types of lock : spin lock, interprocesses locks, semaphores, .
>>> . . And all can be used with the synchronized syntax, and without exposing locking and unlocking primitives.
>>>
>>
>> All works today.
>>
>
> Unless you do some monitor magic, it doesn't.
>
Yes, it does.
-----
class Something {
private:
ReadWriteLock _rw;
public:
this() {
_rw = new ReadWriteLock();
}
void doSomething() shared {
synchronized(_rw.read) {
// do things
}
}
}
-----
I've used this pattern in code. There might be some casting required because the core synchronization primitives haven't been updated to use shared yet.
|
June 03, 2012 Re: synchronized (this[.classinfo]) in druntime and phobos | ||||
---|---|---|---|---|
| ||||
Posted in reply to deadalnix | Am 30.05.2012 11:11, schrieb deadalnix:
>
> D already have much better tools that the one java provide (std.concurency, std.parallelism, TLS by default, transitive type qualifiers, . . .) that most these thing taken from java don't make any sense now.
>
> For instance, what is the point of being able to lock on any object when most of them are thread local ??
Right! Locking on non-TLS objects doesn't make sense. Perhaps only shared objects should be synchronizeable and thus contain a monitor / pointer to a monitor.
|
June 03, 2012 Re: synchronized (this[.classinfo]) in druntime and phobos | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jacob Carlborg | Am 31.05.2012 08:47, schrieb Jacob Carlborg:
> What should have been done is something like this:
>
> 1. Designing feature X
> 2. Show the new feature for the community
> 3. Consider the feedback and possible tweak/redesign
> 4. Implementing in an experimental branch of the compiler
> 5. Release an experimental version with just this feature
> 6. Repeat step 3-5 until satisfied or put on hold/drop the idea
> 7. Prepare Phobos and druntime for the new feature
> 8. Move the implementation to the main branch
> 9. Ship feature X with the next release
> 10. wait
> 11. Fix bugs for feature X
> 12. Repeat step 10-11 a couple of times
> 13. Write about it in TDPL
>
+1
|
June 03, 2012 Re: synchronized (this[.classinfo]) in druntime and phobos | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrew Wiley | Le 03/06/2012 21:40, Andrew Wiley a écrit :
> On Sun, Jun 3, 2012 at 12:29 PM, deadalnix <deadalnix@gmail.com
> <mailto:deadalnix@gmail.com>> wrote:
>
> Le 01/06/2012 22:55, Sean Kelly a écrit :
>
> On Jun 1, 2012, at 5:26 AM, deadalnix wrote:
>
>
> The main drawback is the same as opApply : return (and
> break/continue but it is less relevant for opSynchronized).
> Solution to this problem have been proposed in the past
> using compiler and stack magic.
>
> It open door for stuff like :
> ReadWriteLock rw;
> synchronized(rw.read) {
>
> }
>
> synchronized(rw.write) {
>
> }
>
>
> Opens the door? This works today exactly as outlined above. Or
> am I missing a part of your argument?
>
> And many types of lock : spin lock, interprocesses locks,
> semaphores, . . . And all can be used with the synchronized
> syntax, and without exposing locking and unlocking primitives.
>
>
> All works today.
>
>
> Unless you do some monitor magic, it doesn't.
>
> Yes, it does.
> -----
> class Something {
> private:
> ReadWriteLock _rw;
> public:
> this() {
> _rw = new ReadWriteLock();
> }
> void doSomething() shared {
> synchronized(_rw.read) {
> // do things
> }
> }
> }
> -----
> I've used this pattern in code. There might be some casting required
> because the core synchronization primitives haven't been updated to use
> shared yet.
And where is that ReadWriteLock ?
|
June 04, 2012 Re: synchronized (this[.classinfo]) in druntime and phobos | ||||
---|---|---|---|---|
| ||||
Posted in reply to deadalnix Attachments:
| On Sun, Jun 3, 2012 at 4:39 PM, deadalnix <deadalnix@gmail.com> wrote:
> Le 03/06/2012 21:40, Andrew Wiley a écrit :
>
>> On Sun, Jun 3, 2012 at 12:29 PM, deadalnix <deadalnix@gmail.com <mailto:deadalnix@gmail.com>> wrote:
>>
>> Le 01/06/2012 22:55, Sean Kelly a écrit :
>>
>> On Jun 1, 2012, at 5:26 AM, deadalnix wrote:
>>
>>
>> The main drawback is the same as opApply : return (and
>> break/continue but it is less relevant for opSynchronized).
>> Solution to this problem have been proposed in the past
>> using compiler and stack magic.
>>
>> It open door for stuff like :
>> ReadWriteLock rw;
>> synchronized(rw.read) {
>>
>> }
>>
>> synchronized(rw.write) {
>>
>> }
>>
>>
>> Opens the door? This works today exactly as outlined above. Or
>> am I missing a part of your argument?
>>
>> And many types of lock : spin lock, interprocesses locks,
>> semaphores, . . . And all can be used with the synchronized
>> syntax, and without exposing locking and unlocking primitives.
>>
>>
>> All works today.
>>
>>
>> Unless you do some monitor magic, it doesn't.
>>
>> Yes, it does.
>> -----
>> class Something {
>> private:
>> ReadWriteLock _rw;
>> public:
>> this() {
>> _rw = new ReadWriteLock();
>> }
>> void doSomething() shared {
>> synchronized(_rw.read) {
>> // do things
>> }
>> }
>> }
>> -----
>> I've used this pattern in code. There might be some casting required because the core synchronization primitives haven't been updated to use shared yet.
>>
>
> And where is that ReadWriteLock ?
>
On the GC heap, just like the Monitor object pointed to by __monitor if you mark a method or class as synchronized.
|
June 04, 2012 Re: synchronized (this[.classinfo]) in druntime and phobos | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrew Wiley | Le 04/06/2012 02:03, Andrew Wiley a écrit :
> On Sun, Jun 3, 2012 at 4:39 PM, deadalnix <deadalnix@gmail.com
> <mailto:deadalnix@gmail.com>> wrote:
>
> Le 03/06/2012 21:40, Andrew Wiley a écrit :
>
> On Sun, Jun 3, 2012 at 12:29 PM, deadalnix <deadalnix@gmail.com
> <mailto:deadalnix@gmail.com>
> <mailto:deadalnix@gmail.com <mailto:deadalnix@gmail.com>>> wrote:
>
> Le 01/06/2012 22:55, Sean Kelly a écrit :
>
> On Jun 1, 2012, at 5:26 AM, deadalnix wrote:
>
>
> The main drawback is the same as opApply : return (and
> break/continue but it is less relevant for
> opSynchronized).
> Solution to this problem have been proposed in the past
> using compiler and stack magic.
>
> It open door for stuff like :
> ReadWriteLock rw;
> synchronized(rw.read) {
>
> }
>
> synchronized(rw.write) {
>
> }
>
>
> Opens the door? This works today exactly as outlined
> above. Or
> am I missing a part of your argument?
>
> And many types of lock : spin lock, interprocesses
> locks,
> semaphores, . . . And all can be used with the
> synchronized
> syntax, and without exposing locking and unlocking
> primitives.
>
>
> All works today.
>
>
> Unless you do some monitor magic, it doesn't.
>
> Yes, it does.
> -----
> class Something {
> private:
> ReadWriteLock _rw;
> public:
> this() {
> _rw = new ReadWriteLock();
> }
> void doSomething() shared {
> synchronized(_rw.read) {
> // do things
> }
> }
> }
> -----
> I've used this pattern in code. There might be some casting required
> because the core synchronization primitives haven't been updated
> to use
> shared yet.
>
>
> And where is that ReadWriteLock ?
>
> On the GC heap, just like the Monitor object pointed to by __monitor if
> you mark a method or class as synchronized.
I meant where is the code ?
|
Copyright © 1999-2021 by the D Language Foundation