<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
  <meta content="text/html;charset=ISO-8859-1" http-equiv="Content-Type">
</head>
<body bgcolor="#ffffff" text="#000000">
Sean Kelly wrote:
<blockquote
 cite="mid:1360724B-F8E2-4DD7-A233-FD6BE9ABF2AF@invisibleduck.org"
 type="cite">
  <pre wrap="">On Jan 4, 2010, at 3:13 PM, Graham St Jack wrote:

  </pre>
  <blockquote type="cite">
    <pre wrap="">What is the plan to stop "shared" from spreading through all of an application's code?

My own preference is to adopt an approach that severely limits the number of shared objects, perhaps by using a keyword like "shareable that means: "this object is shared, but it is completely ok to call its synchronized methods from non-shared methods/objects".

This approach facilitates message-passing, and can very simply handle plenty of multi-threaded use-cases. A shareable object whose externally accessible methods are all synchronized and DO NOT accept or return any references to mutable data should be callable from any thread with complete safety, WITHOUT polluting the calling code with "shared".
    </pre>
  </blockquote>
  <pre wrap=""><!---->

I'd planned to ask this a bit later in the discussion, but I've been wondering if all methods need to be labeled as shared or synchronized or if only the public (and possibly protected) ones do?  If I have:

    class A
    {
        void fnA() synchronized { fnB(); } // 1
        void fnB() shared { fnC(); } // 2
        private void fnC() {}
    }

Since fnC() may only be accessed through A's public interface, all of which is ostensibly safe, does fnC() have to be synchronized or shared?  I can see an argument for not allowing case 2, but it does seem safe for fnC() to be called by fnA() at least.  I know D uses recursive locks so there's no functional barrier to making fnC() synchronized, but this seems like it could be horribly slow.  I suppose the compiler could elide additional lock_acquire() calls though, based on static analysis.
  </pre>
</blockquote>
My preference is for fnC() to not be shared, and therefore not
externally available if A is shared.<br>
However, fnC() should be callable from fnA().<br>
<blockquote
 cite="mid:1360724B-F8E2-4DD7-A233-FD6BE9ABF2AF@invisibleduck.org"
 type="cite">
  <pre wrap="">
  </pre>
  <blockquote type="cite">
    <pre wrap="">Within such a shareable object, we can use low-level stuff like mutexes, semaphores and conditions to build the desired behaviour, wrapping it up and presenting a clean interface.
    </pre>
  </blockquote>
  <pre wrap=""><!---->
Since mutexes can override a class' monitor, it already works to do this:

    class A
    {
        this() {
            mut = new Mutex( this );
            cond = new Condition( mut );
        }

        void fnA() synchronized { // locks "mut"
            cond.wait(); // unlocks the lock acquired when fnA() was entered and blocks, etc.
        }

        Mutex mut; Condition cond;
    }

I'm hoping this library-level trick will be enough to allow most of the classic synchronization mechanisms to be used in D 2.0.

  </pre>
  <blockquote type="cite">
    <pre wrap="">Re synchronized containers - I don't like the idea at all. That is going down the path of having many shared objects, which is notoriously difficult to get right, especially for non-experts. IMO, shared objects should be small in number, and serve as boundaries between threads, which otherwise play in their own separate sand-pits.
    </pre>
  </blockquote>
  <pre wrap=""><!---->
A good pathological but functionally correct example is the Thread class in core.thread.  Thread instances should really be labeled as shared, but I know that when this happens the compiler will throw a fit.  The thing is, while some of the methods are already synchronized, there are quite a few which are not and don't need to be and neither do they need the variables they access to be made lock-free.  Even weirder is:

    class Thread
    {
        this( void function() fn ) { m_fn = fn; }
        void start() {
            thread_start( &amp;threadFn, this );
        }
        private void run() { fn(); }
    }

    extern (C) void threadFn( void* x ) {
        Thread t = cast(Thread) x;
        t.run();
    }

Perhaps the shared-violating design here should simply be swept under the rug as TCB implementation details?

  </pre>
  <blockquote type="cite">
    <pre wrap="">Dare I say it - go's emphasis on channels is very appealing to me, and should be something that is easy to do in D - even though it is too limiting to have it as the only tool in the box.
    </pre>
  </blockquote>
  <pre wrap=""><!---->
Channels are a lot like Hoare's CSP model, correct?  ie. you define specific channels where threads may communicate and possibly even what data types may be passed?  This could be built on top of an Erlang-style API without too much fuss, and I've been aiming for the Erlang-style API as the foundation for message passing.  In short, I agree, but that's a conversation for a bit later :-)
  </pre>
</blockquote>
Ok.<br>
</body>
</html>