drcyber
drcyber

Reputation: 151

how to lock a file stream without a mutex

I have been locking/unlocking files in multi-thread applications using something like

void Write_File(FILE* Input_File)
{
        flockfile(Input_File);
        Read_Stuff();
        funlock(Input_File);
}

I want to convert these routines to use streams. I cannot find similar commands to use with streams. Is there any way to lock the file streams without resorting to a mutex?

Upvotes: 2

Views: 1615

Answers (2)

Celada
Celada

Reputation: 22261

flockfile basically is a mutex, at least in glibc, and probably on every other platform as well. So in a sense you are already "resorting to a mutex". If you change to just using a mutex instead nothing will change (as long as all code paths that operate on the file only do so while holding the mutex).

It is important to not confuse flockfile (which is a mutex that manages concurrent file operations between threads of a single process) with system-based advisory file locks, as you'd get with flockf or fcntl(F_SETLK).

Upvotes: 2

jxh
jxh

Reputation: 70502

You can wrap a C style stream around a C++ I/O stream style interface. The example below gives you an idea of how you might implement one using an ostringstream:

class lockedostream_impl : public std::ostringstream
{
    friend class lockedostream;
    struct buf_t : public std::stringbuf {
        FILE *f_;
        buf_t (FILE *f) : f_(f) { flockfile(f_); }
        ~buf_t () { funlockfile(f_); }
        int sync () {
            int r = (f_ ? -(fputs(str().c_str(), f_) == EOF) : 0);
            str(std::string());
            return r;
        }
    } buf_;
    std::ostream & os () { return *this; }
    lockedostream_impl (FILE *f) : buf_(f) { os().rdbuf(&buf_); }
};


class lockedostream {
    typedef std::ostream & (*manip_t) (std::ostream &);
    mutable lockedostream_impl impl_;
public:
    lockedostream (FILE *f) : impl_(f) {}
    template <typename T>
    const lockedostream & operator << (const T &t) const {
        impl_.os() << t;
        return *this;
    }
    const lockedostream & operator << (manip_t m) const {
        impl_.os() << m;
        return *this;
    }
};

You can change the locking primitive however you want, but I maintained your desire to use flockfile() and funlockfile(). With this, you could write code that looked like this:

lockedostream(f)
    << some_stuff_to_be_written
    << some_other_stuff
    << std::endl;

Upvotes: 1

Related Questions