Sun Studio 12: C++ User's Guide

11.4.1.3 MT-Safe iostream Restrictions

The restricted definition of MT-safety for the iostream library means that a number of programming idioms used with iostream are unsafe in a multithreaded environment using shared iostream objects.

Checking Error State

To be MT-safe, error checking must occur in a critical region with the I/O operation that causes the error. The following example illustrates how to check for errors:


Example 11–1 Checking Error State


#include <iostream.h>
enum iostate {IOok, IOeof, IOfail};

iostate read_number(istream& istr, int& num)
{
    stream_locker sl(istr, stream_locker::lock_now);

    istr >> num;

    if (istr.eof()) return IOeof;
    if (istr.fail()) return IOfail;
    return IOok;
}

In this example, the constructor of the stream_locker object sl locks the istream object istr. The destructor of sl, called at the termination of read_number, unlocks istr.

Obtaining Characters Extracted by Last Unformatted Input Operation

To be MT-safe, the gcount function must be called within a thread that has exclusive use of the istream object for the period that includes the execution of the last input operation and gcount call. The following example shows a call to gcount:


Example 11–2 Calling gcount


#include <iostream.h>
#include <rlocks.h>
void fetch_line(istream& istr, char* line, int& linecount)
{
    stream_locker sl(istr, stream_locker::lock_defer);

    sl.lock(); // lock the stream istr
    istr >> line;
    linecount = istr.gcount();
    sl.unlock(); // unlock istr
    ...
}

In this example, the lock and unlock member functions of class stream_locker define a mutual exclusion region in the program.

User-Defined I/O Operations

To be MT-safe, I/O operations defined for a user-defined type that involve a specific ordering of separate operations must be locked to define a critical region. The following example shows a user-defined I/O operation:


Example 11–3 User-Defined I/O Operations


#include <rlocks.h>
#include <iostream.h>
class mystream: public istream {

    // other definitions...
    int getRecord(char* name, int& id, float& gpa);
};

int mystream::getRecord(char* name, int& id, float& gpa)
{
    stream_locker sl(this, stream_locker::lock_now);

    *this >> name;
    *this >> id;
    *this >> gpa;

    return this->fail() == 0;
}