【win32多线程】数据的一致性问题,即多个线程读写数据问题

来源:互联网 发布:ipone5s安装不了软件 编辑:程序博客网 时间:2024/06/11 14:04

1.把锁定搬到更高的层次

void AddLineItems(List *pList)
{
Node node;
while()
{
getLineItem(&item);
AddHead(pList,&node);
}
}


void AddHead(List *pList,Node *pNode)
{
EnterCriticalSection(&pList->critical_sec);
pNode->next=pList->head;
pList->head=pNode;
LeaveCriticalSection(&pList->critical_sec);
}

搬到更高的层次

void AddLineItems(List *pList)
{
Node node;
EnterCriticalSection(&pList->critical_sec);
while()
{
getLineItem(&item);
AddHead(pList,&node);
}
LeaveCriticalSection(&pList->critical_sec);
}

void AddHead(List *pList,Node *pNode)
{
pNode->next=pList->head;
pList->head=pNode;
}

这样的模型有助于windows程序,因为其线程是事件驱动模式,而且常常返回到主消息循环中。


2.读写锁
排他锁看起来不错,但是它会强迫所有的存取操作都按照先后次序来,而多线程的好处也就流失了。这种情况下最好用单一线程。

为Reader锁定
Lock(ReaderMutex)
ReadCount=ReadCount+1;
if(ReadCount==0)
   Unlock(DataSemaphore)
Unlock(ReaderMutex)

为Reader解除锁定
Lock(ReaderMutex)
ReadCount=ReadCount-1;
if(ReadCount==0)
   Unlock(DataSemaphore)
Unlock(ReaderMutex)

为Writer锁定
Lock(DataSemaphore)

为Writer解除锁定
Unlock(DataSemaphore)


实现Reader/Writer的数据结构

ReadWrit.h

typedef struct _RWLock{    // Handle to a mutex that allows    // a single reader at a time access    // to the reader counter.    HANDLEhMutex;    // Handle to a semaphore that keeps    // the data locked for either the    // readers or the writers.    HANDLEhDataLock;    // The count of the number of readers.    // Can legally be zero or one while    // a writer has the data locked.intnReaderCount;} 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);


读者与写者算法:

#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;}


主文件,多读者和写者对链表的操作

#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;    charszBuffer[80];} Node;typedef struct _List{RWLocklock;    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 testingList *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;intrc;intnThreadCount = 0;    DWORDdwThreadId;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 lockif (--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++){intnFoundCount = 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;}


 

原创粉丝点击