Listing 4: Handle class with synchronization

// Copyright (c) 1997 by Bill Reck <breck@magna.com.au>
// This code may be used royalty-free as long as
// this notice appears in the product.

#include <windows.h>
#include <stdio.h>
#include "Handle.h"
#include "AddressRep.h"

class SyncRep {
public:
    SyncRep() : count_(0)
        { ::InitializeCriticalSection(&sync_); }
    ~SyncRep() { ::DeleteCriticalSection(&sync_); }
    void incrRefCount()
        { ::InterlockedIncrement(&count_); }
    void decrRefCount()
        {if (::InterlockedDecrement(&count_) <= 0) delete this;}
    void acquireAccess() { ::EnterCriticalSection(&sync_); }
    void releaseAccess()  { ::LeaveCriticalSection(&sync_); }
private:
    CRITICAL_SECTION sync_;
    LONG count_;
};

template <class REP>
class Access {
public:
    Access(REP *rep) : rep_(rep), acquired_(false) {}
    Access(const  Access<REP> &that)
            : rep_(that.rep_), acquired_(false) {}
    ~Access() { if ( acquired_ ) rep_->releaseAccess(); }
    REP *operator->() {
        if (!acquired_)
            { rep_->acquireAccess(); acquired_ = true; }
        return(rep_);
    }
private:
    REP *rep_;
    bool acquired_;
};
template <class FUNCTOR, class ARG>
class Thread {
public:    
    static HANDLE start(ARG arg) {
        DWORD notUsed;
        ARG *freeStoreArg = new ARG(arg);
        const HANDLE result =
            ::CreateThread(0, 0, base,
                (void*)freeStoreArg, 0, &notUsed);
        if (result == NULL) delete freeStoreArg;
        return(result);
    }
private:    
    static DWORD WINAPI base(void *threadArg) {
        if (threadArg != 0) {
            ARG *freeStoreArg = (ARG*)threadArg;
            ARG stackArg = *freeStoreArg;
            delete freeStoreArg;
            FUNCTOR()(stackArg);
        }
        return(0);
    }
};

template <class H> struct FaxFunctor {
    void operator()(H a) const
        { if (!a.isNull()) a->fax(); }
};

void main(int argc, char *argv[]) {
    // Define the address representation and handle types
    typedef AddressRep< SyncRep > AddrRep;
    typedef Handle< AddrRep, Access<AddrRep> > Address;
    // A quick-n-dirty thread HANDLE collection
    static const maxThreads = MAXIMUM_WAIT_OBJECTS;
    HANDLE threadHandles[maxThreads];
    unsigned threadCount = 0;

    for (int i = 1; i < argc; ++i) {
        // Create a new representation and handle
        Address addr = new AddrRep;
        // Reference a member of the representation
        addr->firstName(argv[i]);
        // Launch several threads for each address
        for (int j = 0; j < 5 && threadCount < maxThreads; ++j)
            threadHandles[threadCount++] =
                Thread<
                    FaxFunctor<Address>, Address>::start(addr);
    }
    ::printf("Waiting for the threads to finish...\n");
    ::WaitForMultipleObjects(
        threadCount, threadHandles, true, INFINITE);
    ::printf("All done\n");
}
//End of File