November 14, 2012
On 11/14/2012 1:23 AM, Benjamin Thaut wrote:
> Could you please give an example where it would break?

Thread 1:
  1. create shared object
  2. pass reference to that object to Thread 2
  3. destroy object

Thread 2:
  1. manipulate that object


> And whats the difference between:
>
> struct Value
> {
>    ~this()
>    {
>      printf("destroy\n");
>    }
> }
>
> shared Value v;
>
>
> and:
>
>
> shared static ~this()
> {
>    printf("destory\n");
> }

The struct declaration of ~this() has no idea what context it will be used in.

November 14, 2012
Am 14.11.2012 11:42, schrieb Walter Bright:
> On 11/14/2012 1:23 AM, Benjamin Thaut wrote:
>> Could you please give an example where it would break?
>
> Thread 1:
>    1. create shared object
>    2. pass reference to that object to Thread 2
>    3. destroy object
>
> Thread 2:
>    1. manipulate that object
>

But for passing a reference to a value type you would have to use a pointer, correct? And pointers are a unsafe feature anyway...
I don't see your point.

And if the use of pointers is allowed, I can make the same case break in a single threaded environment without shared.

Kind Regards
Benjamin Thaut


November 14, 2012
On 11/14/2012 2:49 AM, Benjamin Thaut wrote:
> Am 14.11.2012 11:42, schrieb Walter Bright:
>> On 11/14/2012 1:23 AM, Benjamin Thaut wrote:
>>> Could you please give an example where it would break?
>>
>> Thread 1:
>>    1. create shared object
>>    2. pass reference to that object to Thread 2
>>    3. destroy object
>>
>> Thread 2:
>>    1. manipulate that object
>>
>
> But for passing a reference to a value type you would have to use a pointer,
> correct? And pointers are a unsafe feature anyway...
> I don't see your point.

Pointers are safe. It's pointer arithmetic that is not (and escaping pointers).


> And if the use of pointers is allowed, I can make the same case break in a
> single threaded environment without shared.

1. You can't escape pointers in safe code (well, it's a bug if you do).

2. If the struct is on the heap, it is only destructed if there are no references to it in any thread. If it is not on the heap, and you are in safe code, it should always be destructed safely when it goes out of scope.

This is not so for shared pointers.
November 14, 2012
On Wednesday, November 14, 2012 11:49:22 Benjamin Thaut wrote:
> Am 14.11.2012 11:42, schrieb Walter Bright:
> > On 11/14/2012 1:23 AM, Benjamin Thaut wrote:
> >> Could you please give an example where it would break?
> > 
> > Thread 1:
> >    1. create shared object
> >    2. pass reference to that object to Thread 2
> >    3. destroy object
> > 
> > Thread 2:
> >    1. manipulate that object
> 
> But for passing a reference to a value type you would have to use a
> pointer, correct? And pointers are a unsafe feature anyway...
> I don't see your point.
> 
> And if the use of pointers is allowed, I can make the same case break in a single threaded environment without shared.

Pointers are not considered unsafe at all and are perfectly legal in SafeD. It's ponter _arithmetic_ which is unsafe and therefore considered to be @system.

- Jonathan M Davis
November 14, 2012
Le 14/11/2012 10:31, Jacob Carlborg a écrit :
> On 2012-11-14 10:20, Walter Bright wrote:
>
>> Memory barriers can certainly be added using library functions.
>
> Is there then any real advantage of having it directly in the language?
>

The compiler can do more reordering in regard to barriers. For instance, the compiler may reorder thread local read write accross the barrier.

This can't be done with a library solution.
November 14, 2012
Am 14.11.2012 12:00, schrieb Walter Bright:
> On 11/14/2012 2:49 AM, Benjamin Thaut wrote:
>> Am 14.11.2012 11:42, schrieb Walter Bright:
>>> On 11/14/2012 1:23 AM, Benjamin Thaut wrote:
>>>> Could you please give an example where it would break?
>>>
>>> Thread 1:
>>>    1. create shared object
>>>    2. pass reference to that object to Thread 2
>>>    3. destroy object
>>>
>>> Thread 2:
>>>    1. manipulate that object
>>>
>>
>> But for passing a reference to a value type you would have to use a
>> pointer,
>> correct? And pointers are a unsafe feature anyway...
>> I don't see your point.
>
> Pointers are safe. It's pointer arithmetic that is not (and escaping
> pointers).
>
>
>> And if the use of pointers is allowed, I can make the same case break
>> in a
>> single threaded environment without shared.
>
> 1. You can't escape pointers in safe code (well, it's a bug if you do).
>
> 2. If the struct is on the heap, it is only destructed if there are no
> references to it in any thread. If it is not on the heap, and you are in
> safe code, it should always be destructed safely when it goes out of scope.
>
> This is not so for shared pointers.

So just to be clear, escaping pointers in a single threaded context is a bug. But if you escape them in a multithreaded context its ok?
That sounds inconsistent to me.

But if that is by design your argument is valid.

I still can not think of any real world usecase though where this could actually be used.

A small code example which would break as soon as we allow destructing of shared value types would really be nice. (maybe even in the langauge documentation, because I coudln't find anything)

Kind Regards
Benjamin Thaut

November 14, 2012
On Wednesday, 14 November 2012 at 00:04:56 UTC, deadalnix wrote:
> That is what java's volatile do. It have several uses cases, including valid double check locking (It has to be noted that this idiom is used incorrectly in druntime ATM, which proves both its usefullness and that it require language support) and disruptor which I wanted to implement for message passing in D but couldn't because of lack of support at the time.

What stops you from using core.atomic.{atomicLoad, atomicStore}? I don't know whether there might be a weird spec loophole which could theoretically lead to them being undefined behavior, but I'm sure that they are guaranteed to produce the right code on all relevant compilers. You can even specify the memory order semantics if you know what you are doing (although this used to trigger a template resolution bug in the frontend, no idea if it works now).

David
November 14, 2012
On 2012-11-14 10:30:46 +0000, Timon Gehr <timon.gehr@gmx.ch> said:

> On 11/14/2012 04:12 AM, Michel Fortin wrote:
>> On 2012-11-13 19:54:32 +0000, Timon Gehr <timon.gehr@gmx.ch> said:
>> 
>>> On 11/12/2012 02:48 AM, Michel Fortin wrote:
>>>> I feel like the concurrency aspect of D2 was rushed in the haste of
>>>> having it ready for TDPL. Shared, deadlock-prone synchronized classes[1]
>>>> as well as destructors running in any thread (thanks GC!) plus a couple
>>>> of other irritants makes the whole concurrency scheme completely flawed
>>>> if you ask me. D2 needs a near complete overhaul on the concurrency
>>>> front.
>>>> 
>>>> I'm currently working on a big code base in C++. While I do miss D when
>>>> it comes to working with templates as well as for its compilation speed
>>>> and a few other things, I can't say I miss D much when it comes to
>>>> anything touching concurrency.
>>>> 
>>>> [1]: http://michelf.ca/blog/2012/mutex-synchonization-in-d/
>>> 
>>> I am always irritated by shared-by-default static variables.
>> 
>> I tend to have very little global state in my code,
> 
> So do I. A thread-local static variable does not imply global state. (The execution stack is static.) Eg. in a few cases it is sensible to use static variables as implicit arguments to avoid having to pass them around by copying them all over the execution stack.
> 
> private int x = 0;
> 
> int foo(){
>      int xold = x;
>      scope(exit) x = xold;
>      x = new_value;
>      bar(); // reads x
>      return baz(); // reads x
> }

I'd consider that poor style. Use a struct to encapsulate the state, then make bar, and baz member functions of that struct. The resulting code is cleaner and easier to read:

pure int foo() {
	auto state = State(new_value);
	state.bar();
	return state.baz();
}

You could achieve something similar with nested functions too.


> Unfortunately, this destroys 'pure' even though it actually does not.

Using a local-scoped struct would work with pure, be more efficient (accessing thread-local variables takes more cycles), and be less error-prone while refactoring.

-- 
Michel Fortin
michel.fortin@michelf.ca
http://michelf.ca/

November 14, 2012
On 2012-11-14 12:04, deadalnix wrote:

> The compiler can do more reordering in regard to barriers. For instance,
> the compiler may reorder thread local read write accross the barrier.
>
> This can't be done with a library solution.

I see.

-- 
/Jacob Carlborg
November 14, 2012
On 2012-11-14 11:38, Walter Bright wrote:

> Not that I can think of.

Then we might want to remove it since it's either not working or basically everyone has misunderstood how it should work.

-- 
/Jacob Carlborg
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18