[m-dev.] Interleaved output in hlc.gc.par

Paul Bone paul at bone.id.au
Thu Sep 17 18:09:18 AEST 2015


On Thu, Sep 17, 2015 at 05:32:24PM +1000, Zoltan Somogyi wrote:
> 
> 
> On Thu, 17 Sep 2015 17:01:59 +1000, Paul Bone <paul at bone.id.au> wrote:
> 
> > On Thu, Sep 17, 2015 at 05:00:27PM +1000, Peter Wang wrote:
> > > On Thu, 17 Sep 2015 16:36:42 +1000, Paul Bone <paul at bone.id.au> wrote:
> > > > 
> > > > Should a user reasonably expect calls to io.format to be atomic with respect
> > > > to the IO state?  I ask because this creates an inconsistency.
> > > 
> > > I don't think so.  It is the user's responsibility to serialise any
> > > concurrent uses of the stream.  It's not specific to io.format.
> > > Two threads calling write_string may produce output with interleaved
> > > characters, e.g. "Hweolrllod !"
> > 
> > Oh,
> > 
> > 1) How can users control this for cases when they need to?
> > 2) Why are we writing character by character?!?!
> 
> "We" are not writing anything. Due to this line in library/string.format.m:
> 
> #define ML_USE_SPRINTF MR_TRUE
> 
> calls to io.format are implemented using sprintf. All the threads use
> the same buffer, so it is lucky even that you get all the characters you printed,
> without a character printed by one thread overwriting a character printed
> by another thread.
> 
> To control it, we (the implementors, not Mercury users) would need to surround
> all the C code fragments we invoke that may affect stdio buffers with the *same*
> lock. I believe we already surround such pieces of code with locks, but these locks
> guard only against two threads executing the same *piece of code*, not two
> different pieces of code modifying the same *piece of data*.

I don't know about sprintf, but I believe that printf and fprintf are thread
safe, or maybe that's just glibc..

I just checked runtime/mercury_string.c and MR_make_string which is where
the call to vsnprintf or vsprintf is done (called from string.format.m).
The buffer is either allocated on the stack or the heap (depending on it's
size requirements) and never statically allocated.  The procedure is thread
safe and reentrant.

So this formats the string using a thread-safe buffer, then write_string
writes it out, this eventually calls vfprintf to write the string.
Ultimately the thread-safety of this depends on libc, and I believe that
with glibc this is thread safe (but obviously shouldn't be relied on).

Therefore I believe that the interleaving in the test case's output is due
to the optimisations applied to calls to format to break them up into
separate write operations.


> This would impose serialization of I/O even in cases where different threads
> write to different files, which itself is undesirable. The only good solution
> I can think of is to attach the lock to a Mercury-controlled handle for the
> file pointer.

If necessary that would be best.


-- 
Paul Bone



More information about the developers mailing list