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, 11, 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, 00&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, 00&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

 

posted @ 2010-07-12 14:56  南守拥  阅读(643)  评论(0编辑  收藏  举报