Something needs to happen with shared, and soon.

Walter Bright newshound2 at digitalmars.com
Mon Nov 12 03:19:09 PST 2012


On 11/12/2012 2:57 AM, Johannes Pfau wrote:
> But there are also shared member functions and they're kind of annoying
> right now:
>
> * You can't call shared methods from non-shared methods or vice versa.
>    This leads to code duplication, you basically have to implement
>    everything twice:

You can't get away from the fact that data that can be accessed from multiple 
threads has to be dealt with in a *fundamentally* different way than single 
threaded code. You cannot share code between the two. There is simply no 
conceivable way that "share" can be added and then code will become thread safe.

Most of the issues you're having seem to revolve around treating shared data 
access just like single threaded access, except "share" was added. This cannot 
work. The compiler error messages, while very annoying, are in their own obscure 
way pointing this out.

It's my fault, I have not explained share very well, and have oversold it. It 
does not solve concurrency problems, it points them out.

>
> ----------
> struct ABC
> {
>          Mutext mutex;
> 	void a()
> 	{
> 		aImpl();
> 	}
> 	shared void a()
> 	{
> 		synchronized(mutex)
> 		    aImpl();  //not allowed
> 	}
> 	private void aImpl()
> 	{
> 		
> 	}
> }
> ----------
> The only way to avoid this is casting away shared in the shared a
> method, but that really is annoying.

As I explained, the way to manipulate shared data is to get exclusive access to 
it via a mutex, cast away the shared-ness, manipulate it as single threaded 
data, convert it back to shared, and release the mutex.


>
> * You can't have data members be included only for the shared version.
>    In the above example, the mutex member will always be included, even
>    if ABC instance is thread local.
>
> So you're often better off writing a non-thread safe struct and writing
> a wrapper struct. This way you don't have useless overhead in the
> non-thread safe implementation. But the nice instance syntax is
> lost:
>
> shared(ABC) abc1; ABC abc2;
> vs
> SharedABC abc1; ABC abc2;
>
> even worse, shared propagation won't work this way;
>
> struct DEF
> {
>      ABC abc;
> }
> shared(DEF) def;
> def.abc.a();
>
>
>
> and then there's also the druntime issue: core.sync doesn't work with
> shared which leads to this schizophrenic situation:
> struct A
> {
>      Mutex m;
>      void a() //Doesn't compile with shared
>      {
>          m.lock();  //Compiles, but locks on a TLS mutex!
>          m.unlock();
>      }
> }
>
> struct A
> {
>      shared Mutex m;
>      shared void a()
>      {
>          m.lock();  //Doesn't compile
>          (cast(Mutex)m).unlock(); //Ugly
>      }
> }
>
> So the only useful solution avoids using shared:
> struct A
> {
>      __gshared Mutex m; //Good we have __gshared!
>      shared void a()
>      {
>          m.lock();
>          m.unlock();
>      }
> }

Yes, mutexes will need to exist in a global space.

>
>
> And then there are some open questions with advanced use cases:
> * How do I make sure that a non-shared delegate is only accepted if I
>    have an A, but a shared delegate should be supported
>    for shared(A) and A? (calling a shared delegate from a non-shared
>    function should work, right?)
>
> struct A
> {
>      void a(T)(T v)
>      {
>          writeln("non-shared");
>      }
>      shared void a(T)(T v)  if (isShared!v) //isShared doesn't exist
>      {
>          writeln("shared");
>      }
> }

First, you have to decide what you mean by a shared delegate. Do you mean the 
variable containing the two pointers that make up a delegate are shared, or the 
delegate is supposed to deal with shared data?


>
> And having fun with this little example:
> http://dpaste.dzfl.pl/7f6a4ad2
>
> * What's the difference between: "void delegate() shared"
>    and "shared(void delegate())"?
>
> Error: cannot implicitly convert expression (&a.abc) of type void
> delegate() shared

The delegate deals with shared data.

> to shared(void delegate())

The variable holding the delegate is shared.


> * So let's call it void delegate() shared instead:
> void incrementA(void delegate() shared del)
> /home/c684/c922.d(7): Error: const/immutable/shared/inout attributes
>    are only valid for non-static member functions




More information about the Digitalmars-d mailing list