August 15, 2017
On 8/15/17 5:27 PM, Arek wrote:
> On Tuesday, 15 August 2017 at 10:37:08 UTC, Kagamin wrote:
>> Well, no wrapper is actually needed here:
>>
>> class A
>> {
>>     int method() shared;
>> }
>>
>> void consumer()
>> {
>>     shared a = receiveOnly!(shared A)();
>> }
>>
>> void producer()
>> {
>>     auto cons = spawn(&consumer);
>>     send(cons, new shared A());
>> }
> 
> Yes, but this doesn't compile:
> 
> import std.stdio;
> import std.concurrency;
> 
> struct A
> {
>      int t;
>      int r;
>      int method() shared
>      {
>          return 0;
>      }
> }
> 
> void consumer()
> {
>      shared a = receiveOnly!(shared A)();
> }
> 
> void main()
> {
>      auto cons = spawn(&consumer);
>      send(cons, shared A());
> }

The issue is that send cannot handle shared value types due to a bug in the implementation. In essence, there is no reason to send a shared A -- it's an unrelated copy and not actually shared.

You can send a shared reference to an A just fine:

static shared A a;

send(tid, &a); // works

You *should* be able to send a shared(A). There is no reason to disallow it. But again, it's not super useful.

> This very simple code also doesn't compile:
> 
> shared struct S
> {
>      int i;
> 
>      ~this()
>      {
>      }
> }
> 
> void main()
> {
>      shared s = shared S();
> }
> 
> In general, shared structs with postblit and destructor make problems.

postblit should work.

It does look like destructors are a problem. It appears the compiler attempts to call the destructor while unshared.

-Steve
August 16, 2017
On Tuesday, 15 August 2017 at 21:27:49 UTC, Arek wrote:
> Yes, but this doesn't compile:
>
> import std.stdio;
> import std.concurrency;
>
> struct A
> {
> 	int t;
> 	int r;
> 	int method() shared
> 	{
> 		return 0;
> 	}
> }
>
> void consumer()
> {
> 	shared a = receiveOnly!(shared A)();
> }
>
> void main()
> {
> 	auto cons = spawn(&consumer);
> 	send(cons, shared A());
> }

AIU you use struct as a Unique-like wrapper for shared class object. Extract the object and send it, then wrap again on arrival.
August 16, 2017
On Tuesday, 15 August 2017 at 15:19:02 UTC, Steven Schveighoffer wrote:
> However, I'm not sure about the postblit being called afterward. Does a postblit need to be marked shared in order to work for shared types?

Ideally yes, but it's difficult to come up with a good shared postblit, send and receive is probably the only use case for it :)
August 16, 2017
On 8/16/17 6:23 AM, Kagamin wrote:
> On Tuesday, 15 August 2017 at 15:19:02 UTC, Steven Schveighoffer wrote:
>> However, I'm not sure about the postblit being called afterward. Does a postblit need to be marked shared in order to work for shared types?
> 
> Ideally yes, but it's difficult to come up with a good shared postblit, send and receive is probably the only use case for it :)

Use cases don't matter. What matters is: is it proper for Variant to call the postblit (as it does currently) without regard for the qualifiers?

However, I have found a better way to call postblit that involves the qualifiers than the way Variant currently does it. I'm going to submit a PR to fix these issues.

-Steve
August 16, 2017
On Wednesday, 16 August 2017 at 12:58:25 UTC, Steven Schveighoffer wrote:
> Use cases don't matter. What matters is: is it proper for Variant to call the postblit (as it does currently) without regard for the qualifiers?

Looks like it isn't, https://dpaste.dzfl.pl/183e6dae9867 - shared reference counter with (probably) good enough postblit.
August 16, 2017
On 8/16/17 9:04 AM, Kagamin wrote:
> On Wednesday, 16 August 2017 at 12:58:25 UTC, Steven Schveighoffer wrote:
>> Use cases don't matter. What matters is: is it proper for Variant to call the postblit (as it does currently) without regard for the qualifiers?
> 
> Looks like it isn't, https://dpaste.dzfl.pl/183e6dae9867 - shared reference counter with (probably) good enough postblit.

I have found that shared dtor doesn't work:

struct S
{
  ~this() shared {}
}

void main()
{
   shared S s; // Error: shared method testshared.S.~this is not callable using a non-shared object
}

But shared postblit does work.

Kind of a bummer. Though I think we need some work on the destructors and postblits -- you can't overload them based on qualifiers.

But that isn't a concern for Variant. It is only calling the postblit, which does work.

-Steve
August 16, 2017
On 8/16/17 8:58 AM, Steven Schveighoffer wrote:
> However, I have found a better way to call postblit that involves the qualifiers than the way Variant currently does it. I'm going to submit a PR to fix these issues.

https://github.com/dlang/phobos/pull/5694

-Steve
August 16, 2017
On Tuesday, 15 August 2017 at 21:54:23 UTC, Steven Schveighoffer wrote:
> On 8/15/17 5:27 PM, Arek wrote:
>> On Tuesday, 15 August 2017 at 10:37:08 UTC, Kagamin wrote:
>>> Well, no wrapper is actually needed here:
>>>
[...]
> The issue is that send cannot handle shared value types due to a bug in the implementation. In essence, there is no reason to send a shared A -- it's an unrelated copy and not actually shared.
>
> You can send a shared reference to an A just fine:
>
> static shared A a;
>
> send(tid, &a); // works
>
> You *should* be able to send a shared(A). There is no reason to disallow it. But again, it's not super useful.
>
Yes, I absolutely agree. The object may be shared due to other requirements and there is no reason to reject 'share' qualifier what I want to send/receive it.

>> This very simple code also doesn't compile:
>> 
>> shared struct S
>> {
>>      int i;
>> 
>>      ~this()
>>      {
>>      }
>> }
>> 
>> void main()
>> {
>>      shared s = shared S();
>> }
>> 
>> In general, shared structs with postblit and destructor make problems.
>
> postblit should work.
>
> It does look like destructors are a problem. It appears the compiler attempts to call the destructor while unshared.
>
> -Steve

But I have no idea how and when the object loses its shared nature. Yes, it looks like a bug in dmd. ldc 1.3 doesn't complain in this case.

Arek

August 16, 2017
On Monday, 14 August 2017 at 03:59:48 UTC, Jonathan M Davis wrote:

> The way to handle shared is to protect the section of code that's using the shared object with either a mutex or synchronized block, and then you cast away shared from the object within that section and operate on it as thread-local. When you're done, you make sure that you don't have any thread-local references to the data, and you release the mutex or exit the synchronized block. e.g. something like
>
> shared T sharedObj = getSharedObj();
>
> synchronized(mutex)
> {
>     T nonSharedObj = cast(T)sharedObject
>
>     // do stuff...
>
>     // make sure that no references to nonSharedObj have escaped
> }

Casting objects just to work with it every time is so bad style for me that I even didn't consider such possibility. In fact, I did make something like this but with __gshared both object and mutex. I think I need to review this part of site engine and my programming habits too.
I wonder if it possible and usable to make some template to support this pattern, where we give mutex(es), shared object(s) and delegate to operate with objects as non-shared.

August 17, 2017
On Wednesday, 16 August 2017 at 13:14:55 UTC, Steven Schveighoffer wrote:
> But that isn't a concern for Variant. It is only calling the postblit, which does work.

Shouldn't it call destructor when it goes out of scope?