Thread overview
m_condition.mutex cannot be used in shared method ?
Oct 19, 2014
Marco Leise
Oct 19, 2014
Sean Kelly
Oct 20, 2014
Marco Leise
Oct 20, 2014
Sean Kelly
Oct 21, 2014
Marc Schütz
October 19, 2014
I have a thread that is shared by
others, so I have a shared method, inside of which I wrote:

final void opOpAssign(string op : "~")(ref StreamingObject item) shared
{
	synchronized (m_condition.mutex)
	{
		m_list.unshared ~= item;
		m_condition.notify();
	}
}

Error: non-shared method core.sync.condition.Condition.mutex is not callable using a shared object

Where exactly should my stuff stop to be shared so I can call .mutex ?

Btw.:
StreamingObject is a struct
unshared is a @property that casts away sharedness

-- 
Marco

October 19, 2014
On Sunday, 19 October 2014 at 13:42:05 UTC, Marco Leise wrote:
> I have a thread that is shared by
> others, so I have a shared method, inside of which I wrote:
>
> final void opOpAssign(string op : "~")(ref StreamingObject item) shared
> {
> 	synchronized (m_condition.mutex)
> 	{
> 		m_list.unshared ~= item;
> 		m_condition.notify();
> 	}
> }
>
> Error: non-shared method core.sync.condition.Condition.mutex is not callable using a shared object
>
> Where exactly should my stuff stop to be shared so I can call .mutex ?

What really needs to happen is for everything in core.sync to be made shared.  I got partway through this at one point and stopped, because it was imposing a terrible design on the classes--I had shared methods that were casting away shared and then calling the non-shared methods to do the work.

The reason for this was that the transitivity of shared was preventing me from calling pthread_mutex_lock or whatever because those functions didn't take a shared pthread_mutex_t.  And attempting to rewrite core.sys.posix to make the logically shared types explicitly shared had a cascading effect that made me uncomfortable.

Because of this, I remain unconvinced that the semantics of the shared attribute are actually correct when applied to user-defined types.  I want some kind of an "I know what I'm doing" label, perhaps equivalent to the "mutable" attribute in C++, but to exempt contained types from shared.
October 20, 2014
Am Sun, 19 Oct 2014 17:09:22 +0000
schrieb "Sean Kelly" <sean@invisibleduck.org>:

> What really needs to happen is for everything in core.sync to be made shared.  I got partway through this at one point and stopped, because it was imposing a terrible design on the classes--I had shared methods that were casting away shared and then calling the non-shared methods to do the work.
> 
> The reason for this was that the transitivity of shared was preventing me from calling pthread_mutex_lock or whatever because those functions didn't take a shared pthread_mutex_t.  And attempting to rewrite core.sys.posix to make the logically shared types explicitly shared had a cascading effect that made me uncomfortable.
> 
> Because of this, I remain unconvinced that the semantics of the shared attribute are actually correct when applied to user-defined types.  I want some kind of an "I know what I'm doing" label, perhaps equivalent to the "mutable" attribute in C++, but to exempt contained types from shared.

Thank you for that honest response. The situation is really bizarre. I just tried to create a shared worker thread and there is no ctor in Thread that creates a shared instance.

Is a shared constructor even meaningful? [1]
If yes, what do we need it for?

Can't we otherwise just implicitly and safely cast to shared
_after_ the constructor ran when we write `new shared(Foo)(...)`?

Casting away shared is not @safe. Since this is normal to
do in synchronized blocks, I figure the whole core.Thread and
core.sync.xxx family are @system functionality ?


[1]
(Note that I created a PR for DMD that disables shared
destruction:
https://github.com/D-Programming-Language/dmd/pull/4072)

-- 
Marco

October 20, 2014
On Monday, 20 October 2014 at 09:53:23 UTC, Marco Leise wrote:
>
> Thank you for that honest response. The situation is really
> bizarre. I just tried to create a shared worker thread and
> there is no ctor in Thread that creates a shared instance.
>
> Is a shared constructor even meaningful? [1]

If we want to try for having thread-local memory pools then yes.


> If yes, what do we need it for?

See above.  Though there are other problems that will probably
prevent this anyway (immutable being implicitly shared, for one).


> Can't we otherwise just implicitly and safely cast to shared
> _after_ the constructor ran when we write `new shared(Foo)(...)`?

Yep.


> Casting away shared is not @safe. Since this is normal to
> do in synchronized blocks, I figure the whole core.Thread and
> core.sync.xxx family are @system functionality ?

Yes.  Though I really don't like feeling that casts are necessary
in general.  If I have to cast in order to do normal work then
there's probably something wrong with the type system.  Though
I'll note that I also use "mutable" in C++ for what I feel are
completely justifiable reasons (like on a contained Mutex so I
can lock/unlock some region of code in a const method), and D has
been firmly established in opposition to logical const.  Mutexes
are actually a special case in D because they bypass normal type
checking thanks to the way synchronized blocks work, and I'm sure
we could do something similar for shared, but it feels wrong.  I
kind of hope that someone will show me that casting away shared
isn't necessary, kind of like how Monads are a clever response to
immutability in Haskell.


> [1]
> (Note that I created a PR for DMD that disables shared
> destruction:
> https://github.com/D-Programming-Language/dmd/pull/4072)

With all the recent work on the GC, we really really need to
start tracking which thread owns a given non-shared object so it
can be finalized properly.  This may mean having the process of
casting away shared make the executing thread the new owner of
the object.
October 21, 2014
On Monday, 20 October 2014 at 17:37:22 UTC, Sean Kelly wrote:
> With all the recent work on the GC, we really really need to
> start tracking which thread owns a given non-shared object so it
> can be finalized properly.  This may mean having the process of
> casting away shared make the executing thread the new owner of
> the object.

But this change of ownership is usually only temporary:

    with(cast(BaseType) sharedVar) {
        // ...
    }