Jump to page: 1 2
Thread overview
synchronize issues
Aug 20, 2001
Kevin Quick
Aug 21, 2001
Walter
Aug 21, 2001
Kevin Quick
Aug 26, 2001
Dan Hursh
Aug 26, 2001
Walter
Aug 27, 2001
Walter
Aug 27, 2001
Kevin Quick
Aug 27, 2001
Tobias Weingartner
Aug 27, 2001
Dan Hursh
Aug 21, 2001
Bradeeoh
Aug 23, 2001
Walter
Aug 24, 2001
Kevin Quick
Aug 24, 2001
Russ Lewis
Aug 27, 2001
Kevin Quick
Aug 25, 2001
Walter
Aug 27, 2001
Kevin Quick
Aug 23, 2001
Walter
August 20, 2001
I would recommend against keeping the "synchronize" keyword.

* Implementing this requires a knowledge of the current hardware
  environment (UP v.s. SMP).  While a simple test-and-set spinloop
  would presumably never conflict in a UP environment, it's still
  overhead, especially because this may require cache synchronization
  wait cycles.

* What if the statement is a complex statement?
  - The synchronization requirement may not follow code scoping.  For
    example, how would the following C excerpt be re-coded to be as
    efficient code in D?

        thread_lock(X);
        while (protected_test) {
            if (protected_test2) {
                thread_unlock(X);
                return;
            }
            if (protected_test3) continue;
            thread_unlock(X);
            do_lots_of_stuff;
            thread_lock(X);
          increment_pvar:
            protected_var += 1;
            thread_unlock(X);
            do_lots_more_stuff;
            read(open_fildesc, buf, 100);
            thread_lock(X);
        }

  - Scope management now has to include sychronization shells, which
    can become very complex, especially with the "goto" statement.
    Not only must synchronization be released, on a goto out of
    the complex statement, but they must also be acquired on goto into
    the statement.  Continuing the above example, what if code later on
    stated:

        thread_lock(Y);
        if (a_different_protected_test) {
            thread_unlock(Y);
            thread_lock(X);
            goto increment_pvar;
        } else
            thread_unlock(Y);

* For synchronization related to an Object (using the Expression), how
  are multiple disparate or nested synchronizations handled?

        synchronize ( my_obj ) {
            do_part_1;
            func_a(my_obj);
            do_part_2;
            func_a(a_different_obj);
        }

        func_a(an_obj) {
        {
            synchronize (an_obj) {
                an_obj++;
            }
        }

  Is the second synchronize allowed?  If so, how much storage do you
  reserve in Object for synchronization state?  I'll want that so that
  when the another thread calls "func_a(a_different_obj)" while the
  first is in "do_part_2" that I can figure out how the deadlock
  occurred.

* The statement makes assumptions about the underlying OS's scheduling
  model, and may not provide the richness or scheduling capabilities
  that the OS's scheduler provides.
  - Is this a pre-emptable threads model so that spinning on one thread
    will let the scheduler interrupt?
  - If the object is locked, the OS might decide to schedule the thread
    holding the object.

* I think this will interfere with the determinism that a real-time
  application would desire:  The more code protected by a spinlock,
  the greater the range of CPU spin times and the more imprecise the
  real-time determinism becomes.


-- 
________________________________________________________________________ Kevin Quick                  Surgient Networks               Project UDI kevin.quick@surgient.com      Austin,  Texas                      Editor +1 512 241 4801              www.surgient.com         www.projectudi.org
August 21, 2001
Synchronized statements are not a new idea, they work well in other
languages. They're basically just syntactic sugar around a try-finally
construct, where the first statement in the try acquires the mutex and the
finally releases it. Any operating system that supports multithreaded
programming should be able to provide a suitable primitive mutex
object. -Walter


Kevin Quick wrote in message ...
>
>I would recommend against keeping the "synchronize" keyword.
>
>* Implementing this requires a knowledge of the current hardware
>  environment (UP v.s. SMP).  While a simple test-and-set spinloop
>  would presumably never conflict in a UP environment, it's still
>  overhead, especially because this may require cache synchronization
>  wait cycles.
>
>* What if the statement is a complex statement?
>  - The synchronization requirement may not follow code scoping.  For
>    example, how would the following C excerpt be re-coded to be as
>    efficient code in D?
>
>        thread_lock(X);
>        while (protected_test) {
>            if (protected_test2) {
>                thread_unlock(X);
>                return;
>            }
>            if (protected_test3) continue;
>            thread_unlock(X);
>            do_lots_of_stuff;
>            thread_lock(X);
>          increment_pvar:
>            protected_var += 1;
>            thread_unlock(X);
>            do_lots_more_stuff;
>            read(open_fildesc, buf, 100);
>            thread_lock(X);
>        }
>
>  - Scope management now has to include sychronization shells, which
>    can become very complex, especially with the "goto" statement.
>    Not only must synchronization be released, on a goto out of
>    the complex statement, but they must also be acquired on goto into
>    the statement.  Continuing the above example, what if code later on
>    stated:
>
>        thread_lock(Y);
>        if (a_different_protected_test) {
>            thread_unlock(Y);
>            thread_lock(X);
>            goto increment_pvar;
>        } else
>            thread_unlock(Y);
>
>* For synchronization related to an Object (using the Expression), how
>  are multiple disparate or nested synchronizations handled?
>
>        synchronize ( my_obj ) {
>            do_part_1;
>            func_a(my_obj);
>            do_part_2;
>            func_a(a_different_obj);
>        }
>
>        func_a(an_obj) {
>        {
>            synchronize (an_obj) {
>                an_obj++;
>            }
>        }
>
>  Is the second synchronize allowed?  If so, how much storage do you
>  reserve in Object for synchronization state?  I'll want that so that
>  when the another thread calls "func_a(a_different_obj)" while the
>  first is in "do_part_2" that I can figure out how the deadlock
>  occurred.
>
>* The statement makes assumptions about the underlying OS's scheduling
>  model, and may not provide the richness or scheduling capabilities
>  that the OS's scheduler provides.
>  - Is this a pre-emptable threads model so that spinning on one thread
>    will let the scheduler interrupt?
>  - If the object is locked, the OS might decide to schedule the thread
>    holding the object.
>
>* I think this will interfere with the determinism that a real-time
>  application would desire:  The more code protected by a spinlock,
>  the greater the range of CPU spin times and the more imprecise the
>  real-time determinism becomes.
>
>
>--
>________________________________________________________________________ Kevin Quick                  Surgient Networks               Project UDI kevin.quick@surgient.com      Austin,  Texas                      Editor +1 512 241 4801              www.surgient.com         www.projectudi.org


August 21, 2001
"Walter" <walter@digitalmars.com> writes:

> Synchronized statements are not a new idea, they work well in other
> languages. They're basically just syntactic sugar around a try-finally
> construct, where the first statement in the try acquires the mutex and the
> finally releases it. Any operating system that supports multithreaded
> programming should be able to provide a suitable primitive mutex
> object. -Walter

By your last sentence you appear to by tying D to a specific operating system implementation, since D will have to generate mutex calls specific to the operating system.

The C language is pure and can be implemented anywhere.

It sounds like D is restricted to:
  * A specific operating system for which it generates the right mutex
    calls?
  * The subset of operating systems that are thread-based

Defining D as a new language is a noble effort... keep the language pure and portable, don't target x86, Linux, *nix, or any other specific environment.

Your first sentence isn't much of an answer either... are those languages intended to operate at the same level as C and D, or are they higher-level languages which have less focus on implementation? One of the attractions C has held for so long is that it provides a (usually) reasonable balance between higher-order programmatic abstractions and lower-level implementation control; D should have the same goal if it seeks to gain similar levels of acceptance.

Have you analyzed the implementation of synchronization in those other languages relative to the issues raised in my original post?  Those are legitimate implementation issues and you need to at least have an answer for them even if you retain the synchronize statement.

-Kevin

P.S. Along the lines of language purity, my next recommendation would be
to drop the asm statement:
  * It forces you to maintain two languages, not one, and to implement the
    compiler accordingly.
  * It introduces impure LOW-LEVEL non-portable elements into the code
  * Modern build and link tools are good enough that any desired assembly
    can be implemented in .s files, run through a separate assembler, and
    then linked with the D-generated code.  Modern linkers can still
    perform inline optimization to provide efficiency.
  * This allows ABI-specific elements to be placed in ABI-specific
    locations, rather than being embedded in core code (an issue I
    noticed in a separate thread here as well).

-- 
________________________________________________________________________ Kevin Quick                  Surgient Networks               Project UDI kevin.quick@surgient.com      Austin,  Texas                      Editor +1 512 241 4801              www.surgient.com         www.projectudi.org
August 21, 2001
Kevin Quick wrote:
> P.S. Along the lines of language purity, my next recommendation would be
> to drop the asm statement:
>   * It forces you to maintain two languages, not one, and to implement the
>     compiler accordingly.
>   * It introduces impure LOW-LEVEL non-portable elements into the code
>   * Modern build and link tools are good enough that any desired assembly
>     can be implemented in .s files, run through a separate assembler, and
>     then linked with the D-generated code.  Modern linkers can still
>     perform inline optimization to provide efficiency.
>   * This allows ABI-specific elements to be placed in ABI-specific
>     locations, rather than being embedded in core code (an issue I
>     noticed in a separate thread here as well).

Ah, on this note, while I don't feel strongly one way or another about the presence/absence of an asm statement, I _do_ think that "volatile" should be retained in D; if you have reasonably portable multithreading, the volatile attribute is very useful and far more portable than inline asm. Not to mention that it shouldn't be difficult to implement for a compiler savant. :)

Alternately, maybe there's something you can do with a synchronize block to ensure that variables are always reloaded on their first use within a synch -- i.e. implicitly volatile.

(Ooh! "synch"! There's your solution to synchronize/synchronise!)

-RB
August 21, 2001
I think if Walter decides to gear the language he is developing towards multi-threading operating systems, that's his peroggative.  :)  As longs as it's platform independant amongst those o/ses   :)

-Brady

"Kevin Quick" <kevin.quick@surgient.com> wrote in message news:m3u1z1cvqt.fsf@surgient.com...
>
> "Walter" <walter@digitalmars.com> writes:
>
> > Synchronized statements are not a new idea, they work well in other languages. They're basically just syntactic sugar around a try-finally construct, where the first statement in the try acquires the mutex and
the
> > finally releases it. Any operating system that supports multithreaded programming should be able to provide a suitable primitive mutex object. -Walter
>
> By your last sentence you appear to by tying D to a specific operating system implementation, since D will have to generate mutex calls specific to the operating system.
>
> The C language is pure and can be implemented anywhere.
>
> It sounds like D is restricted to:
>   * A specific operating system for which it generates the right mutex
>     calls?
>   * The subset of operating systems that are thread-based
>
> Defining D as a new language is a noble effort... keep the language pure and portable, don't target x86, Linux, *nix, or any other specific environment.
>
> Your first sentence isn't much of an answer either... are those languages intended to operate at the same level as C and D, or are they higher-level languages which have less focus on implementation? One of the attractions C has held for so long is that it provides a (usually) reasonable balance between higher-order programmatic abstractions and lower-level implementation control; D should have the same goal if it seeks to gain similar levels of acceptance.
>
> Have you analyzed the implementation of synchronization in those other languages relative to the issues raised in my original post?  Those are legitimate implementation issues and you need to at least have an answer for them even if you retain the synchronize statement.
>
> -Kevin
>
> P.S. Along the lines of language purity, my next recommendation would be
> to drop the asm statement:
>   * It forces you to maintain two languages, not one, and to implement the
>     compiler accordingly.
>   * It introduces impure LOW-LEVEL non-portable elements into the code
>   * Modern build and link tools are good enough that any desired assembly
>     can be implemented in .s files, run through a separate assembler, and
>     then linked with the D-generated code.  Modern linkers can still
>     perform inline optimization to provide efficiency.
>   * This allows ABI-specific elements to be placed in ABI-specific
>     locations, rather than being embedded in core code (an issue I
>     noticed in a separate thread here as well).
>
> --
> ________________________________________________________________________ Kevin Quick                  Surgient Networks               Project UDI kevin.quick@surgient.com      Austin,  Texas                      Editor +1 512 241 4801              www.surgient.com         www.projectudi.org


August 23, 2001
"Bradeeoh" <bradeeoh@crosswinds.net> wrote in message news:9lu77h$2glk$1@digitaldaemon.com...
> I think if Walter decides to gear the language he is developing towards multi-threading operating systems, that's his peroggative.  :)  As longs
as
> it's platform independant amongst those o/ses   :)

If the platform doesn't support multiple threads, then the synchronize statement would just revert to a no-op.


August 23, 2001
"Kevin Quick" <kevin.quick@surgient.com> wrote in message news:m3u1z1cvqt.fsf@surgient.com...
> P.S. Along the lines of language purity, my next recommendation would be
> to drop the asm statement:
>   * It forces you to maintain two languages, not one, and to implement the
>     compiler accordingly.
>   * It introduces impure LOW-LEVEL non-portable elements into the code
>   * Modern build and link tools are good enough that any desired assembly
>     can be implemented in .s files, run through a separate assembler, and
>     then linked with the D-generated code.  Modern linkers can still
>     perform inline optimization to provide efficiency.
>   * This allows ABI-specific elements to be placed in ABI-specific
>     locations, rather than being embedded in core code (an issue I
>     noticed in a separate thread here as well).

I relied for years on a separate assembler. The trouble was, there were always random bugs in random versions of the assembler. Couple that with Microsoft kept changing the syntax of the asm, and even kept revamping the command line interface. It was just a lot of grief. Implementing the inline asm in the C compiler just eliminated these problems - I had a consistent, reliable assembler to use.

If there is no asm statement in D, then I'd be using the native C compiler for its asm statement. If you've ever tried gcc's inline assembler, you'll know why that's a bad idea!

Yes, of course, inline assembler is not portable between CPUs. But it *is* portable between, say, win32 and linux, and I see its primary use is in implementing system dependent code anyway.


August 24, 2001
"Walter" <walter@digitalmars.com> writes:
> 
> If the platform doesn't support multiple threads, then the synchronize statement would just revert to a no-op.


I'm afraid I'm still unconvinced.

Linux has several implementations of threads available, including pthreads and sstthreads (http://sourceforge.net/projects/ssthreads/). Because of this, D itself has to be rebuilt depending on which threads package I'm intending to use, even on the same platform.

This also removes any binary portability of D output... I can't take a D exectuable I built on Linux and run it on another POSIX x86 OS.

-Kevin

August 24, 2001
Kevin Quick wrote:

> "Walter" <walter@digitalmars.com> writes:
> >
> > If the platform doesn't support multiple threads, then the synchronize statement would just revert to a no-op.
>
> I'm afraid I'm still unconvinced.
>
> Linux has several implementations of threads available, including pthreads and sstthreads (http://sourceforge.net/projects/ssthreads/). Because of this, D itself has to be rebuilt depending on which threads package I'm intending to use, even on the same platform.
>
> This also removes any binary portability of D output... I can't take a D exectuable I built on Linux and run it on another POSIX x86 OS.

Why not dynamically link your D executable with a library?  You could export your threading features to a binary library.  Better yet, export it to a .d module; then the author of that .d module can call a C function directly, include assembly language code, or just declare the function (which means that D will look for it in a library you import).


August 25, 2001
I confess I don't see the problem. D binaries will be as portable or unportable as C ones. The source will be more portable, as with the synchronize statement you needn't know or care which threading library is used.

Kevin Quick wrote in message ...
>"Walter" <walter@digitalmars.com> writes:
>>
>> If the platform doesn't support multiple threads, then the synchronize statement would just revert to a no-op.
>
>
>I'm afraid I'm still unconvinced.
>
>Linux has several implementations of threads available, including pthreads and sstthreads (http://sourceforge.net/projects/ssthreads/). Because of this, D itself has to be rebuilt depending on which threads package I'm intending to use, even on the same platform.
>
>This also removes any binary portability of D output... I can't take a D exectuable I built on Linux and run it on another POSIX x86 OS.
>
>-Kevin
>


« First   ‹ Prev
1 2