多线程同步中的读者写者问题-windows 平台实现

来源:互联网 发布:软件数据线 安卓 编辑:程序博客网 时间:2024/04/19 16:47

前一段时间在项目开发中遇到了经典的读者写者问题,这里给出简单的程序实现。

程序中用了一个互斥体 Mutex 和一个信号量 Semaphore, 当然也可以使用

两个信号量。

1: ReaderWriterLock.h, 该文件定义了读写锁的类

#ifndef ReaderWriterLock_H
#define ReaderWriterLock_H

class ReaderWriterLock
{
protected:
 HANDLE readMutex;
 HANDLE writeSemaph;
 int numReaders;

public:
 ReaderWriterLock()
 {
  numReaders = 0;

  // create 1 Mutex and 1 Semaphore
  // 2 Semaphore also OK
  readMutex = CreateMutex(NULL, false, NULL);
  writeSemaph = CreateSemaphore(NULL, 1, 1, NULL);
  if (readMutex == NULL || writeSemaph == NULL)
  {
   MessageBox(NULL, "create mutex failed!" , NULL, 0);
  }
 }

 ~ReaderWriterLock()
 {
  CloseHandle(readMutex);
  CloseHandle(writeSemaph);
 }

 inline void ReaderLock()
 {
  // lock readMutex for readers to access numReaders
  WaitForSingleObject(readMutex, INFINITE);
  numReaders++;
  if (numReaders == 1)
  {
   // for first reader, lock writeSemaph
   WaitForSingleObject(writeSemaph, INFINITE);
  }
  ReleaseMutex(readMutex);
 }

 inline void ReaderUnLock()
 {
  // lock readMutex for readers to access numReaders
  WaitForSingleObject(readMutex, INFINITE);
  numReaders--;
  if (numReaders == 0)
  {
   // for last reader, unlock writeSemaph
   ReleaseSemaphore(writeSemaph, 1, NULL);
  }
  ReleaseMutex(readMutex);
 }

 inline void WriterLock()
 {
  // lock writeSemaph for writers to access shared object
  WaitForSingleObject(writeSemaph, INFINITE);
 }

 inline void WriterUnLock()
 {
  // unlock writeSemaph for writers to access shared object
  ReleaseSemaphore(writeSemaph, 1, NULL);
 }
};

#endif

2:ReaderWriter.cpp, 该文件是测试程序,在 VC++6 中调试通过

// ReaderWriter.cpp : Defines the entry point for the application.
//

#include "stdafx.h"

#include <process.h>
#include <time.h>
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <string>

#include "ReaderWriterLock.h"

char sharedStr[128]="this is a shared string !";
char logFile[128]="d://log.txt";
ReaderWriterLock* rwLock=new ReaderWriterLock();

void readerProc(void* param);
void writerProc(void* param);
void WriteLogStr(char* s);

using namespace std;

int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow)
{
  // TODO: Place code here.
 int readerId;
 int writerId;
 FILE* f;

 // clear the log
 f = fopen(logFile, "w");
 fclose(f);

 //rwLock = new ReaderWriterLock();
 srand(time(0));

 readerId = 1;
 _beginthread(readerProc, 0, (void*)&readerId);
 Sleep(10);

 writerId = 1;
 _beginthread(writerProc, 0, (void*)&writerId);
 Sleep(10);

 readerId = 2;
 _beginthread(readerProc, 0, (void*)&readerId);
 Sleep(10);

 writerId = 2;
 _beginthread(writerProc, 0, (void*)&writerId);
 Sleep(10);

 readerId = 3;
 _beginthread(readerProc, 0, (void*)&readerId);

 // running for 5s
 Sleep(5000);

 return 0;
}

void readerProc(void* param)
{
 int myid;
 char idStr[128];
 char str[128];

 myid = *((int*)(param));
 itoa(myid, idStr, 10);

 strcpy(str, "reader ");
 strncat(str, idStr, 128);
 strcat(str, " begin......");

 //cout << "reader " << myid << " begin......" << endl;
 WriteLogStr(str);

 while (true)
 {
  // first sleep a random time : between 1 - 5 s
  int sleepTime;
  sleepTime = 1 + (int)(5.0*rand()/(RAND_MAX+1.0));
  Sleep(sleepTime*10);

  // prepare str
  strcpy(str, "reader ");
  strncat(str, idStr, 128);
  strcat(str, " is reading the shared string :    ");

  // then access the shared var
  rwLock->ReaderLock();
   strncat(str, sharedStr, 128);
  rwLock->ReaderUnLock();

  //cout << "reader " << myid << " is reading the shared string : " << sharedStr << endl;
  WriteLogStr(str);
 }
}

void writerProc(void* param)
{
 int myid;
 char idStr[128];
 char str[128];

 myid = *((int*)(param));
 itoa(myid, idStr, 10);

 strcpy(str, "writer ");
 strncat(str, idStr, 128);
 strcat(str, " begin......");

 //cout << "reader " << myid << " begin......" << endl;
 WriteLogStr(str);

 while (true)
 {
  // get a random char
  int randChar;
  randChar = myid + (int)(5.0*rand()/(RAND_MAX+1.0));
  randChar += 40;

  // then access the shared var
  rwLock->WriterLock();
   for (int i=0; i<20; i++)
   {
    sharedStr[i] = randChar;
    Sleep(1);
   }
   sharedStr[20] = 0; // append a '/0' to end a string

   strcpy(str, "writer ");
   strncat(str, idStr, 128);
   strcat(str, " is writing the shared string to : ");
   strncat(str, sharedStr, 128);
  rwLock->WriterUnLock();

  //cout << "reader " << myid << " is reading the shared string : " << sharedStr << endl;
  WriteLogStr(str);
 }
}

void WriteLogStr(char* s)
{
 FILE* f;

 f = fopen(logFile, "a");
 if (f != NULL)
 {
  fwrite(s, strlen(s), 1, f);
  fwrite("/n", 1, 1, f);
 }

 fclose(f);
}