The key point of this follow-up email is: we are looking for user input
on how sync and single variables should work when passing them as
arguments to functions with generic formals.
For 1.10, write() et al. on sync/single will generate a compiler error.
We made this choice to raise community awareness and to avoid users
getting surprising behavior from whatever other option we might have
implemented.
min()/max() on sync/single/atomic will generate a compiler error, too.
We will stick with this unless we hear strong arguments/proposals to the
contrary.
In both the above cases, to perform the desired operation on a
sync/single, you will need to invoke readFE()/readFF()/readXX() etc.
explicitly, then pass the result to write()/min() etc. For example:
var mySync$: sync int;
var mySingle$: single real;
... start computing the above ...
//Currently the following would generate compiler errors like:
// "IO.chpl:1691: error: sync/single variables cannot currently be
written"
//Run chpl --print-callstack-on-error to determine the source location.
//
// writeln("mySync$ = ", mySync$);
// writeln("mySingle$ = ", mySingle$);
//Specify the desired access explicitly.
// E.g. write a pair of (is it full?, the value), non-atomically:
writeln("mySync$ = ", (mySync$.isFull, mySync$.readXX()));
// or wait until the variable is full:
writeln("mySingle$ = ", mySingle$.readFF());
The above solution is not perfect because:
* If you have a record/class with a sync/single field, you will need to
provide your own writeThis() method to enable write() on that
record/class to compile. Without it the compiler provides a default
implementation that invokes writeThis on each field. The latter
currently generates a compiler error for sync/single fields.
For example:
record RecordWithSync {
var regularField: int;
var syncField$: sync real;
proc writeThis(x: Writer) {
x.write("(", regularField, ", ", syncField$.readXX(), ")");
}
}
var r: RecordWithSync;
// This would generate a compiler error without writeThis() above.
// Since we used readXX() there, this will never block.
writeln(r);
* It is not symmetric with reading sync/single variables, for which it
seems natural to wait until such a variable is empty and leave it full.
Disclaimer: currently read() does not work on sync/single; this will not
be fixed for 1.10.
Some of the questions we'd like input on are:
* What should write() do on a sync/single? Examples:
- Not allowed (it's the current implementation).
- "Consume" the full/empty state, i.e. implicitly do
sync.readFE() or single.readFF().
- Wait for, but not consume, the full state, i.e.
implicitly do readFF() for sync and single.
- Do not wait for the full state - print whether it's full.
Example 1: "5.5" (when full), "<empty>" (when empty).
Example 2: "f:5.5" (when full), "e:5.5" (when empty).
- Others?
* What should write() do on a class/record containing a sync/single
field, without user-defined writeThis or readWriteThis? Examples:
- Do write() on the sync/single field, behaving according to the
choice in the previous bullet.
- Do something special, e.g. never "consume" the full/empty state of
each field, like the last option in the previuos bullet.
- Others?
* What should read() do on a sync/single? E.g. should it wait for the
variable to become empty before storing a value into it? Or should it
read in and set the variable's full/empty bit, besides reading the value?
There is more discussion in the commit message for the #420 merge, see:
https://github.com/chapel-lang/chapel/commit/6c2e3a6
For example, it shows a new deadlock that our earlier implementation
could result in, when a thread locked the channel before locking the
sync variable.
Vass
On 09/16/14 09:02, Brad Chamberlain wrote:
> Hi all --
>
> As you may have seen/heard on github, Vass is working on a bug fix for the
> long-term problem of passing sync/single to generic arguments: Previously,
> such cases were unwrapped and treated as reads of the actual argument,
> passing in the underlying value with no full/empty state. Thus, in:
>
> proc foo(x) {
> ...
> }
>
> var mySyncVar$: sync int;
>
> foo(mySyncVar$);
>
> foo() would be interpreted as taking an int and the foo(mySyncVar$) would be
> interpreted as foo(mySyncVar$.readFE()). This has seemed inconsistent to
> most of us for some time now, the original rationale for it didn't seem to
> hold up as the language has matured, and it is something I attempted to fix a
> year ago without success. Vass has been more successful this month
> (motivated by his work to get is*Type()-style queries working correctly for
> all types).
>
> One place where this has impact is in the implementation of write/writeln for
> sync/single, which were previously treated as a blocking read of the value
> and passing the value to the corresponding write/writeln for its base type.
> It has always seemed unfortunate/surprising to me (and to users, I believe)
> to have such cases consume the full/empty state, and has led to buggy
> programs, so what I've proposed we do for this release is to reinterpret
> write/writeln as an inspection of the sync/single variable's full state,
> writing:
>
> "<empty>", if the variable is empty
> its value, if the variable is full
>
> The rationale for this is that when you're writing something, I believe
> you're typically wanting to inspect its logical state, not treat it as a
> consumption of the value. And that if someone wants the previous behavior,
> they would call their own readFE/readFF at the callsite, passing the base
> value on to the write/writeln call. I think that this is a nice change and
> improvement, but it's clearly a significant change so I wanted other
> developers to be able to protest if they thought it was clearly wrong --
> particularly if they had a better proposal. Or if it seems like too
> big/scary a change to make so close to the release.
>
> Similarly, and less significantly, min()/max() are defined generically and as
> a result, used to perform a readFE/readFF of a sync/single argument at the
> callsite and then just operate on the base value. In the new "pass the
> sync/single by ref" interpretation, the generic implementations don't work
> because they trip over the full/empty state. Our proposal here is to not
> support min()/max() on synchronized types, requiring users to do the
> readFE/readFF at the callsite if they want to perform min()/max() on the
> value being wrapped by the sync/single. Thus, in Vass's patch, passing
> min()/max() a sync or single (or atomic) results in a compiler error
> explaining that those routines are not supported for said types.
>
> I think this semantic fix is long overdue and that the ensuing changes are
> nice steps forward as well. Moreover, I think that the fix makes it worth
> taking the changes even at this late date in the 1.10 release cycle. But if
> there's a strong feeling that we should hold off until after the 1.10 branch
> is cut, I'd like to hear that.
>
> Thanks,
> -Brad
------------------------------------------------------------------------------
Slashdot TV. Video for Nerds. Stuff that Matters.
http://pubads.g.doubleclick.net/gampad/clk?id=160591471&iu=/4140/ostg.clktrk
_______________________________________________
Chapel-developers mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/chapel-developers