7-1

ReadWrit.h
/*
 * ReadWrit.h
 *
 * Sample code for Multithreading Applications in Win32
 * This is from Chapter 7, Listing 7-1
 *
 * Demonstrates an implementation of the
 * Readers/Writers algorithm. This version
 * gives preference to readers.
 
*/

////////////////////////////////////////////////////// /

//
//  Structure definition
//

typedef 
struct  _RWLock
{
    
//  Handle to a mutex that allows
    
//  a single reader at a time access
    
//  to the reader counter.
    HANDLE    hMutex;

    
//  Handle to a semaphore that keeps
    
//  the data locked for either the
    
//  readers or the writers.
    HANDLE    hDataLock;

    
//  The count of the number of readers.
    
//  Can legally be zero or one while
    
//  a writer has the data locked.
     int         nReaderCount;
} RWLock;

//
//  Reader/Writer prototypes
//

BOOL InitRWLock(RWLock 
* pLock);
BOOL DestroyRWLock(RWLock 
* pLock);
BOOL AcquireReadLock(RWLock 
* pLock);
int  ReleaseReadLock(RWLock  * pLock);
BOOL AcquireWriteLock(RWLock 
* pLock);
int  ReleaseWriteLock(RWLock  * pLock);
BOOL ReadOK(RWLock 
* pLock);
BOOL WriteOK(RWLock 
* pLock);

BOOL FatalError(
char   * s);

 

代码
/*
 * ReadWrit.c
 *
 * Sample code for "Multithreading Applications in Win32"
 * This is from Chapter 7, various listings.
 *
 * Demonstrates an implementation of the
 * Readers/Writers algorithm. This version
 * gives preference to readers.
 
*/

#define  WIN32_LEAN_AND_MEAN
#include 
< stdio.h >
#include 
< stdlib.h >
#include 
< windows.h >
#include 
" ReadWrit.h "

//  If we wait more than 2 seconds, then something is probably wrong!
#define  MAXIMUM_TIMEOUT 2000

//  Here's the pseudocode for what is going on:
//
//  Lock for Reader:
//   Lock the mutex
//   Bump the count of readers
//   If this is the first reader, lock the data
//   Release the mutex
//
//  Unlock for Reader:
//   Lock the mutex
//   Decrement the count of readers
//   If this is the last reader, unlock the data
//   Release the mutex
//
//  Lock for Writer:
//   Lock the data
//
//  Unlock for Reader:
//   Unlock the data

////////////////////////////////////////////////////// /

BOOL MyWaitForSingleObject(HANDLE hObject)
{
    DWORD result;

    result 
=  WaitForSingleObject(hObject, MAXIMUM_TIMEOUT);
    
//  Comment this out if you want this to be non-fatal
     if  (result  !=  WAIT_OBJECT_0)
        FatalError(
" MyWaitForSingleObject - Wait failed, you probably forgot to call release! " );
    
return  (result  ==  WAIT_OBJECT_0);
}

BOOL InitRWLock(RWLock 
* pLock)
{
    pLock
-> nReaderCount  =   0 ;
    pLock
-> hDataLock  =  CreateSemaphore(NULL,  1 1 , NULL);
    
if  (pLock -> hDataLock  ==  NULL)
        
return  FALSE;
    pLock
-> hMutex  =  CreateMutex(NULL, FALSE, NULL);
    
if  (pLock -> hMutex  ==  NULL)
    {
        CloseHandle(pLock
-> hDataLock);
        
return  FALSE;
    }
    
return  TRUE;
}

BOOL DestroyRWLock(RWLock 
* pLock)
{
    DWORD result 
=  WaitForSingleObject(pLock -> hDataLock,  0 );
    
if  (result  ==  WAIT_TIMEOUT)
        
return  FatalError( " DestroyRWLock - Can't destroy object, it's locked! " );

    CloseHandle(pLock
-> hMutex);
    CloseHandle(pLock
-> hDataLock);
    
return  TRUE;
}

BOOL AcquireReadLock(RWLock 
* pLock)
{
    BOOL result 
=  TRUE;

    
if  ( ! MyWaitForSingleObject(pLock -> hMutex))
        
return  FALSE;
 
    
if ( ++ pLock -> nReaderCount  ==   1 )
        result 
=  MyWaitForSingleObject(pLock -> hDataLock);

    ReleaseMutex(pLock
-> hMutex);
    
return  result;
}

BOOL ReleaseReadLock(RWLock 
* pLock)
{
    
int  result;
    LONG lPrevCount;

    
if  ( ! MyWaitForSingleObject(pLock -> hMutex))
        
return  FALSE;

    
if  ( -- pLock -> nReaderCount  ==   0 )
        result 
=  ReleaseSemaphore(pLock -> hDataLock,  1 & lPrevCount);

    ReleaseMutex(pLock
-> hMutex);
    
return  result;
}

BOOL AcquireWriteLock(RWLock 
* pLock)
{
    
return  MyWaitForSingleObject(pLock -> hDataLock);
}

BOOL ReleaseWriteLock(RWLock 
* pLock)
{
    
int  result;
    LONG lPrevCount;

    result 
=  ReleaseSemaphore(pLock -> hDataLock,  1 & lPrevCount);
    
if  (lPrevCount  !=   0 )
        FatalError(
" ReleaseWriteLock - Semaphore was not locked! " );
    
return  result;
}

BOOL ReadOK(RWLock 
* pLock)
{
    
//  This check is not perfect, because we
    
//  do not know for sure if we are one of
    
//  the readers.
     return  (pLock -> nReaderCount  >   0 );
}

BOOL WriteOK(RWLock 
* pLock)
{
    DWORD result;

    
//  The first reader may be waiting in the mutex,
    
//  but any more than that is an error.
     if  (pLock -> nReaderCount  >   1 )
        
return  FALSE;

    
//  This check is not perfect, because we
    
//  do not know for sure if this thread was
    
//  the one that had the semaphore locked.
    result  =  WaitForSingleObject(pLock -> hDataLock,  0 );
    
if  (result  ==  WAIT_TIMEOUT)
        
return  TRUE;

    
//  a count is kept, which was incremented in Wait.
    result  =  ReleaseSemaphore(pLock -> hDataLock,  1 , NULL);
    
if  (result  ==  FALSE)
        FatalError(
" WriteOK - ReleaseSemaphore failed " );
    
return  FALSE;
}

////////////////////////////////////////////////////// /

/*
 * Error handler
 
*/
BOOL FatalError(
char   * s)
{
    fprintf(stdout, 
" %s\n " , s);
    
//  Comment out exit() to prevent termination
    exit(EXIT_FAILURE);
    
return  FALSE;
}

 

代码
/*
 * List.c
 *
 * Sample code for "Multithreading Applications in Win32"
 * This is from Chapter 7, Listing 7-1
 *
 * Demonstrates an implementation of the
 * Readers/Writers algorithm. This version
 * gives preference to readers.
 
*/

#define  WIN32_LEAN_AND_MEAN
#include 
< stdio.h >
#include 
< stdlib.h >
#include 
< windows.h >
#include 
" ReadWrit.h "

////////////////////////////////////////////////////// /

//
//  Structure definition
//

typedef 
struct  _Node
{
    
struct  _Node  * pNext;
    
char     szBuffer[ 80 ];
} Node;

typedef 
struct  _List
{
    RWLock    
lock ;
    Node    
* pHead;
} List;

//
//  Linked list prototypes
//

BOOL InitRWLock(RWLock 
* pLock);
BOOL DeleteList(List 
* pList);
BOOL AddHead(List 
* pList, Node  * node);
BOOL DeleteHead(List 
* pList);
BOOL Insert(List 
* pList, Node  * afterNode, Node  * newNode);
Node 
* Next(List  * pList, Node  * node);

//
//  Test functions prototypes
//

DWORD WINAPI LoadThreadFunc(LPVOID n);
DWORD WINAPI SearchThreadFunc(LPVOID n);
DWORD WINAPI DeleteThreadFunc(LPVOID n);

//
//  Global variables
//

//  This is the list we use for testing
List  * gpList;

////////////////////////////////////////////////////// /

List 
* CreateList()
{
    List 
* pList  =  GlobalAlloc(GPTR,  sizeof (List));
    
if  (InitRWLock( & pList -> lock ==  FALSE)
    {
        GlobalFree(pList);
        pList 
=  NULL;
    }
    
return  pList;
}

BOOL DeleteList(List 
* pList)
{
    AcquireWriteLock(
& pList -> lock );
    
while  (DeleteHead(pList))
        ;
    ReleaseWriteLock(
& pList -> lock );

    DestroyRWLock(
& gpList -> lock );

    GlobalFree(pList);

    
return  TRUE;
}

BOOL AddHead(List 
* pList, Node  * pNode)
{
    
if  ( ! WriteOK( & pList -> lock ))
        
return  FatalError( " AddHead - not allowed to write! " );

    pNode
-> pNext  =  pList -> pHead;
    pList
-> pHead  =  pNode;
}

BOOL DeleteHead(List 
* pList)
{
    Node 
* pNode;

    
if  ( ! WriteOK( & pList -> lock ))
        
return  FatalError( " AddHead - not allowed to write! " );

    
if  (pList -> pHead  ==  NULL)
        
return  FALSE;

    pNode 
=  pList -> pHead -> pNext;
    GlobalFree(pList
-> pHead);
    pList
-> pHead  =  pNode;
    
return  TRUE;
}

BOOL Insert(List 
* pList, Node  * afterNode, Node  * newNode)
{
    
if  ( ! WriteOK( & pList -> lock ))
        
return  FatalError( " Insert - not allowed to write! " );

    
if  (afterNode  ==  NULL)
    {
        AddHead(pList, newNode);
    }
    
else
    {
        newNode
-> pNext  =  afterNode -> pNext;
        afterNode
-> pNext  =  newNode;
    }
}

Node 
* Next(List  * pList, Node  * pNode)
{
    
if  ( ! ReadOK( & pList -> lock ))
    {
        FatalError(
" Next - Not allowed to read! " );
        
return  NULL;
    }

    
if  (pNode  ==  NULL)
        
return  pList -> pHead;
    
else
        
return  pNode -> pNext;
}

////////////////////////////////////////////////////// /

DWORD WINAPI ThreadFunc(LPVOID);

int  main()
{
    HANDLE  hThrds[
4 ];
    
int      slot  =   0 ;
    
int         rc;
    
int         nThreadCount  =   0 ;
    DWORD    dwThreadId;

    gpList 
=  CreateList();
    
if  ( ! gpList)
        FatalError(
" main - List creation failed! " );

    hThrds[nThreadCount
++ =  CreateThread(NULL,
        
0 , LoadThreadFunc,  0 0 & dwThreadId );

    hThrds[nThreadCount
++ =  CreateThread(NULL,
        
0 , SearchThreadFunc, (LPVOID) " pNode " 0 & dwThreadId );

    hThrds[nThreadCount
++ =  CreateThread(NULL,
        
0 , SearchThreadFunc, (LPVOID) " pList " 0 & dwThreadId );

    hThrds[nThreadCount
++ =  CreateThread(NULL,
        
0 , DeleteThreadFunc,  0 0 & dwThreadId );

    
/*  Now wait for all threads to terminate  */
    rc 
=  WaitForMultipleObjects(
        nThreadCount,
        hThrds,
        TRUE,
        INFINITE );

    
for  (slot = 0 ; slot < nThreadCount; slot ++ )
        CloseHandle(hThrds[slot]);
    printf(
" \nProgram finished.\n " );

    DeleteList(gpList);

    
return  EXIT_SUCCESS;
}

/*
 * Slowly load the contents of "List.c" into the
 * linked list.
 
*/
DWORD WINAPI LoadThreadFunc(LPVOID n)
{
    
int  nBatchCount;
    Node 
* pNode;

    FILE
*  fp  =  fopen( " List.c " " r " );
    
if  ( ! fp)
    {
        fprintf(stderr, 
" ReadWrit.c not found\n " );
        exit(EXIT_FAILURE);
    }

    pNode 
=  GlobalAlloc(GPTR,  sizeof (Node));
    nBatchCount 
=  (rand()  %   10 +   2 ;
    AcquireWriteLock(
& gpList -> lock );

    
while  (fgets(pNode -> szBuffer,  sizeof (Node), fp))
    {
        AddHead(gpList, pNode);

        
//  Try not to hog the lock
         if  ( -- nBatchCount  ==   0 )
        {
            ReleaseWriteLock(
& gpList -> lock );
            Sleep(rand() 
%   5 );
            nBatchCount 
=  (rand()  %   10 +   2 ;
            AcquireWriteLock(
& gpList -> lock );
        }
        pNode 
=  GlobalAlloc(GPTR,  sizeof (Node));
    }

    ReleaseWriteLock(
& gpList -> lock );
    
return   0 ;
}


/*
 * Every so often, walked the linked list
 * and figure out how many lines one string
 * appears (given as the startup param)
 
*/
DWORD WINAPI SearchThreadFunc(LPVOID n)
{
    
int  i;
    
char   * szSearch  =  ( char   * )n;

    
for  (i = 0 ; i < 20 ; i ++ )
    {
        
int         nFoundCount  =   0 ;
        Node   
* next  =  NULL;

        AcquireReadLock(
& gpList -> lock );
        next 
=  Next(gpList, next);
        
while  (next)
        {
            
if  (strstr(next -> szBuffer, szSearch))
                nFoundCount
++ ;
            next 
=  Next(gpList, next);
        }

        ReleaseReadLock(
& gpList -> lock );

        printf(
" Found %d lines with '%s'\n " , nFoundCount, szSearch);
        Sleep((rand() 
%   30 ));
    }
    
return   0 ;
}


/*
 * Every so often, delete some entries in the list.
 
*/
DWORD WINAPI DeleteThreadFunc(LPVOID n)
{
    
int  i;

    
for  (i = 0 ; i < 100 ; i ++ )
    {
        Sleep(
1 );
        AcquireWriteLock(
& gpList -> lock );
        DeleteHead(gpList);
        DeleteHead(gpList);
        DeleteHead(gpList);
        ReleaseWriteLock(
& gpList -> lock );
    }

    
return   0 ;
}

od

 

你可能感兴趣的:(7-1)