February 01, 2010
Le 2010-02-01 ? 16:49, Andrei Alexandrescu a ?crit :

> I think swap could be typed as:
> 
> swap(scope ref int[], scope ref int[]);
> 
> The point of scope parameter typechecking is that swap does not save a reference surreptitiously; I think escaping to another scope parameter should be fine (if somewhat conservative).

It's not safe unless the compiler enforcse that all scoped parameters belong to the same owner object. Otherwise you could exchange them between too different objects and unless there is no aliasing they'd now each be owned by two locks!


> In fact I've had this idea for a while now that "ref" should imply "I won't escape it". That would make ref strictly pass-down. Walter is mildly favorable to that idea. I think it's worth giving it a closer look now.

This has some far-reaching consequences: since the 'this' of a struct is a 'ref', you wouldn't be able to take the address of a member.


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



February 01, 2010
Fawzi Mohamed wrote:
> I gave a quick reading about the fact that reading needs a lock because
> otherwise it might not be updated almost forever, this is (as far as I
> know) wrong.
> Yes the view of one thread might be offset with respect with the one of
> another, but not indefinitely so.
> The main reason to put the sync is to ensure that one sees a consistent
> view of the value.
> If a value is always updated in an atomic way then the sync is not needed.

It's a classic that if you read (without handshake) a value in a loop thinking you're doing spinning, various compiler and processor optimizations will cache the value and spin forever. The synchronization in there is needed for the handshake, and can be optimized by the compiler if a simple barrier is needed.

But no handshake == incorrect code.


Andrei
February 01, 2010
Robert Jacques wrote:
> Scope needs to prevent escaping to any scope, which most importantly includes other scope variables. i.e.:
> 
> shared int[] x;
> int[] y;
> swap(x,y);
> 
> Causes a unshared array to become shared.

That won't typecheck for other reasons.

There might be an issue, but the above doesn't describe it.

Andrei
February 01, 2010
Michel Fortin wrote:
> Le 2010-02-01 ? 16:49, Andrei Alexandrescu a ?crit :
> 
>> I think swap could be typed as:
>>
>> swap(scope ref int[], scope ref int[]);
>>
>> The point of scope parameter typechecking is that swap does not save a reference surreptitiously; I think escaping to another scope parameter should be fine (if somewhat conservative).
> 
> It's not safe unless the compiler enforcse that all scoped parameters belong to the same owner object. Otherwise you could exchange them between too different objects and unless there is no aliasing they'd now each be owned by two locks!

Could you please give an example?

>> In fact I've had this idea for a while now that "ref" should imply "I won't escape it". That would make ref strictly pass-down. Walter is mildly favorable to that idea. I think it's worth giving it a closer look now.
> 
> This has some far-reaching consequences: since the 'this' of a struct is a 'ref', you wouldn't be able to take the address of a member.

You can take the address, you can't escape it, which is fine. Also, you can pass down a ref to the field, which is kind of the purpose of the limitation.


Andrei
February 01, 2010
Le 2010-02-01 ? 16:10, Andrei Alexandrescu a ?crit :

> * most functions do take scope parameters, so probably @escaping should be the explicit attribute

Perhaps, but I'm not sure about that. 'scope', being a restriction, is limited to the function where you put it. 'scope' forces the functions it calls to abide by the restriction, just like 'const', @safe, 'nothrow', 'pure', or (perhaps surprisingly) 'deprecated'. It always work that way in D.

This way someone not caring about our little multithreading problems can write a full program without even thinking about 'scope'. This is hardly true for @escaping.

This should somewhat lessen the aggravation.

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



February 01, 2010
Michel Fortin wrote:
> Le 2010-02-01 ? 16:10, Andrei Alexandrescu a ?crit :
> 
>> * most functions do take scope parameters, so probably @escaping should be the explicit attribute
> 
> Perhaps, but I'm not sure about that. 'scope', being a restriction, is limited to the function where you put it.

That's exactly the problem if the assumption that scoped parameters are 90% of them. It would cause a lot of code to gratuitously not work and a lot of annotations to be added.

Andrei
February 01, 2010
On 1-feb-10, at 23:10, Andrei Alexandrescu wrote:

> Fawzi Mohamed wrote:
>> I gave a quick reading about the fact that reading needs a lock
>> because otherwise it might not be updated almost forever, this is
>> (as far as I know) wrong.
>> Yes the view of one thread might be offset with respect with the
>> one of another, but not indefinitely so.
>> The main reason to put the sync is to ensure that one sees a
>> consistent view of the value.
>> If a value is always updated in an atomic way then the sync is not
>> needed.
>
> It's a classic that if you read (without handshake) a value in a loop thinking you're doing spinning, various compiler and processor optimizations will cache the value and spin forever. The synchronization in there is needed for the handshake, and can be optimized by the compiler if a simple barrier is needed.

you don't need a barrier, you need a volatile statement to avoid compiler optimizations

>
> But no handshake == incorrect code.
>
>
> Andrei
> _______________________________________________
> dmd-concurrency mailing list
> dmd-concurrency at puremagic.com
> http://lists.puremagic.com/mailman/listinfo/dmd-concurrency

February 01, 2010
Le 2010-02-01 ? 17:21, Andrei Alexandrescu a ?crit :

> Michel Fortin wrote:
>> Le 2010-02-01 ? 16:10, Andrei Alexandrescu a ?crit :
>>> * most functions do take scope parameters, so probably @escaping should be the explicit attribute
>> Perhaps, but I'm not sure about that. 'scope', being a restriction, is limited to the function where you put it.
> 
> That's exactly the problem if the assumption that scoped parameters are 90% of them. It would cause a lot of code to gratuitously not work and a lot of annotations to be added.

To be more precise it'd cause a lot of code to not work when called from a synchronized function. Weren't we saying synchronized objects would be a rare thing?


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



February 01, 2010
Le 2010-02-01 ? 17:16, Andrei Alexandrescu a ?crit :

> Michel Fortin wrote:
>> Le 2010-02-01 ? 16:49, Andrei Alexandrescu a ?crit :
>>> I think swap could be typed as:
>>> 
>>> swap(scope ref int[], scope ref int[]);
>>> 
>>> The point of scope parameter typechecking is that swap does not save a reference surreptitiously; I think escaping to another scope parameter should be fine (if somewhat conservative).
>> It's not safe unless the compiler enforcse that all scoped parameters belong to the same owner object. Otherwise you could exchange them between too different objects and unless there is no aliasing they'd now each be owned by two locks!
> 
> Could you please give an example?

Sure. Here is a List class, each item being a reference to unsynchronized objects. (Items could be anything with a reference or a pointer.)

	class Item { // not synchronized
		string name;
		int quantity;
	}

	synchronized class List {
		Item[] all;
		Item current;

		this() {
			all = new Item[5];
			foreach (ref item; all) {
				all = new Item();
			}
			current = all[0];
		}
	}

Now run this code:

	List list1 = new List();
	List list2 = new List();

	synchronized (this, other) {
		swap(this.current, other.current);
	}

This makes each class take the current item of the other, but at the same time keeping a reference in its 'all' array. Synchronizing with either one of the List could give you access to the swapped items, so it could result in two threads accessing it at the same time.

So you should get an error when calling swap here:

	synchronized (this, other) {
		swap(this.current, other.current);
		// Error! this.current and other.current are not protected by the
		// same lock.
	}

The compiler need to know 'swap' wants the owner of the two variables to be the same, so either all 'scope' arguments are said to have the same owner, or we have a way to make two argument have the same scope, perhaps by giving each scope a name or a number: 'scope!1'.


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



February 01, 2010
Le 2010-02-01 ? 17:26, Fawzi Mohamed a ?crit :

> On 1-feb-10, at 23:10, Andrei Alexandrescu wrote:
> 
>> Fawzi Mohamed wrote:
>>> I gave a quick reading about the fact that reading needs a lock because otherwise it might not be updated almost forever, this is (as far as I know) wrong.
>>> Yes the view of one thread might be offset with respect with the one of another, but not indefinitely so.
>>> The main reason to put the sync is to ensure that one sees a consistent view of the value.
>>> If a value is always updated in an atomic way then the sync is not needed.
>> 
>> It's a classic that if you read (without handshake) a value in a loop thinking you're doing spinning, various compiler and processor optimizations will cache the value and spin forever. The synchronization in there is needed for the handshake, and can be optimized by the compiler if a simple barrier is needed.
> 
> you don't need a barrier, you need a volatile statement to avoid compiler optimizations

Is that something the compiler could do in an optimization pass, I mean determining when a barrier isn't necessary and volatile is enough? For instance when periodically checking a shared variable in a loop?

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