User`s guide

Cray XMT Programming Environment Users Guide
In the previous code, flag$ controls access to file f, ensuring that the combination
of fseek and fread are executed atomically. In this case, you use SEEK_SET
because the SEEK_CUR (positioning relative to the current position) is not useful in
a parallel context.
Example 6. Preventing racing when calling I/O functions
You use a similar technique when using ferror with another call to ensure that
any error detected by the ferror call was not caused by a racing read or write
call from a different thread. For example, in the following code, calls to several I/O
functions are grouped together so that they are all executed atomically.
sync int flag$ = 1;
#pragma mta assert parallel
for (i = 0; i < n; i++)
{
Buf buffer;
int err;
int j = flag$; // lock
fseek(f, i*sizeof(Buf), SEEK_SET);
fread(buffer, sizeof(Buf), 1, f);
err = ferror(f);
flag$ = j; // unlock
if (!err)
{
// Work with buffer
}
}
In the previous code, the result of the call to ferror is saved to a variable (err) for
later testing.
The same considerations apply when using futures or more complex loops, perhaps
with the I/O hidden within a nest of procedure calls. Single calls always execute
atomically. However, when a sequence of calls pertaining to a single file must be
executed atomically, you must manage the sequence of calls explicitly.
Internally, the stdio library enforces locking for each FILE object (FILE is a data
type defined in stdio.h). This causes output to a number of different files can
proceed in parallel, but output to a single file is serialized. Similarly, you can use
sprintf and sscanf independently of calls to other functions because these
functions do not use a FILE object. For example, for the loop in the following
example, every iteration refers to a different FILE object, so each call to fprintf
can run without interfering with files used by another iteration.
#pragma mta assert parallel
for (i = 0; i < n; i++)
{
fprintf(f[i],"this is iteration %d\n", i);
}
38 S247920