User`s guide
Developing an Application [3]
Example 8. Using synchronization with UNIX I/O functions
To correct this problem, you can either rewrite the code in the style of the first
example or add some sort of explicit synchronization, as shown in the following
example.
sync int flag$ = 1;
char part1[80];
int len1 = sprintf(part1, "this is iteration ");
#pragma mta assert parallel
for (i = 0; i < n; i++)
{
char part2[80];
int len2 = sprintf(part2, "%d\n", i);
int j = flag$; // lock
write(fd, part1, len1);
write(fd, part2, len2);
flag$ = j; // unlock
}
The previous code manipulates the sync variable flag$ to create an atomic section
that contains two calls to write. The actual value loaded from and stored to flag$
is not important because the code uses flag$ as a lock.
Example 9. Using synchronization with UNIX record-oriented I/O functions
For record-oriented I/O, you can use explicit synchronization to ensure the correct
behavior by using a combination of lseek together with a read or write
operation, such as in the following code example.
sync int flag$ = 1;
#pragma mta assert parallel
for (i = 0; i < n; i++)
{
Buf buffer;
int j = flag$; // lock
lseek(fd, i*sizeof(Buf), SEEK_SET);
read(fd, buffer, sizeof(Buf));
flag$ = j; // unlock
//Work with buffer
}
In the previous code, flag$ controls access to file fd, ensuring that the combination
of lseek and read are executed atomically. In this case, you use SEEK_SET
because SEEK_CUR is not useful in a parallel context.
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 explicitly.
S–2479–20 41