您的位置:首页 > 其它

Windows操作系统实习之读者-写者问题

2008-01-06 15:56 369 查看
实习环境:

系统为Windows XP + VC 6.0

实习目标:

在Windows XP下创建一个控制台进程,该进程应包含n个线程。用这n个线程来表示n个读者或写者。每个线程按相应测试数据文件(后面介绍)的要求进行读写操作。用信号量机制分别实现读者优先和写者优先的读者-写者问题。

读者-写者问题的操作限制(包括读者优先和写者优先):

1)写-写互斥,即不能有两个写者同时进行写操作。

2)读-写互斥,即不能同时有一个线程在读,而另一个线程在写。

3)读-读互斥,即可以有一个或多个读者在读。

读者优先的附加限制:如果一个读者申请进行读操作时已有另一个读者正在进行读操作,则该读者可直接开始读操作。

写者优先的附加限制:如果一个读者申请进行读操作时已有另一个写者在等待访问共享资源,则该读者必须等到没有写者出于等待状态后才能开始读操作。

测试文件格式说明,下面是一个测试数据文件的例子:

1 R 3 5
2 W 4 5
3 R 5 2
4 R 6 5
5 W 5.1 3
6 R 15 4
7 R 15 4

程序代码:

// file Prj1.cpp
// author: Melody_1208
// date: 2008-1-6
//
/////////////////////////////////////////////////////////

#include "windows.h"
#include <conio.h>
#include <stdlib.h>
#include <stdio.h>
#include <fstream.h>

#define READER 'R' // reader
#define WRITER 'W' // writer
#define INTE_PER_SEC 1000 // interrupt number per second
#define MAX_THREAD_NUM 64 // max thread number

int readcount = 0;
int writecount = 0;

CRITICAL_SECTION RP_Write; // Critical Section
CRITICAL_SECTION cs_Write;
CRITICAL_SECTION cs_Read;

struct ThreadInfo
{
int serial; // the serial number of the thread.
char entity; // type of thread(reader or writer).
double delay; // delay of thread.
double persist; // time fo thread's read and write operation.
};

void RP_ReaderThread(void *p);
void RP_WriterThread(void *p);
void ReaderPriority(char * file);

void WP_ReaderThread(void *p);
void WP_WriterThread(void *p);
void WriterPriority(char * file);

// the main function
int main(int argc, char *argv[])
{
char ch;
while(true)
{
printf("************************************************/n");
printf(" 1: Reader Priority/n");
printf(" 2: Writer Priority/n");
printf(" 3: Exit to Windows/n");
printf("************************************************/n");
printf("Enter your choice(1,2 or 3): ");
// input is incorrect.
do{
ch = (char)_getch();
}while(ch != '1' && ch != '2' && ch != '3');

// clear the screen.
system("cls");
// choose 3, return.
if(ch == '3')
return 0;
// choose 1, reader first.
else if(ch == '1')
ReaderPriority("thread.dat");
// choose 2, writer first.
else
WriterPriority("thread.dat");
// end.
printf("/nPress Any Key To Continue:");
_getch();
system("cls");
}

return 0;
}

void RP_ReaderThread(void *p)
{
// execlusive object
HANDLE h_Mutex;
h_Mutex = OpenMutex(MUTEX_ALL_ACCESS, FALSE, "mutex_for_readcount");

DWORD wait_for_mutex; // wait for the execlusive object
DWORD m_delay; // delay time
DWORD m_persist; // the time of read file operation
int m_serial; // serial number of the thread

// get the information from the parameter.
m_serial = ((ThreadInfo *)(p))->serial;
m_delay = (DWORD)(((ThreadInfo *)(p))->delay*INTE_PER_SEC);
m_persist = (DWORD)(((ThreadInfo *)(p))->persist*INTE_PER_SEC);
Sleep(m_delay); // wait for a little while.

printf("Reader thread %d sents the reading require./n", m_serial);

// wait for execlusive signal,
wait_for_mutex = WaitForSingleObject(h_Mutex, -1);
// add the reader's number
readcount++;
if(readcount == 1)
{
// the first reader,wait for resource.
EnterCriticalSection(&RP_Write);
}
ReleaseMutex(h_Mutex); // release execlusive signal

// read the file.
printf("Reader thread %d begins to read file./n", m_serial);
Sleep(m_persist);

// exit the thread
printf("Reader thread %d finished reading file./n", m_serial);
wait_for_mutex = WaitForSingleObject(h_Mutex, -1);
// decrement the reader's number
readcount--;
if(readcount == 0)
{
// if all readers finished their operation, wake up the writer
LeaveCriticalSection(&RP_Write);
printf("Reader thread %d leave the critical section./n", m_serial);
}
ReleaseMutex(h_Mutex); // release the execlusive signal
}

void RP_WriterThread(void *p)
{
DWORD m_delay;
DWORD m_persist;
int m_serial;
// get infomation from the parameter.
m_serial = ((ThreadInfo *)(p))->serial;
m_delay = (DWORD)(((ThreadInfo *)(p))->delay*INTE_PER_SEC);
m_persist = (DWORD)(((ThreadInfo *)(p))->persist*INTE_PER_SEC);
Sleep(m_delay); // wait

printf("Writer thread %d sents the writing require./n", m_serial);
// wait for the resource
EnterCriticalSection(&RP_Write);

// write the file
printf("Writer thread %d begins to write to the file./n", m_serial);
Sleep(m_persist);

// exit the thread
printf("Writer thread %d finishing writing to the file./n", m_serial);

// release the resource
LeaveCriticalSection(&RP_Write);
}

void ReaderPriority(char * file)
{
DWORD n_thread = 0; // number of threads
DWORD thread_ID; // thread ID
DWORD wait_for_all; // wait for all threads

// execlusive object
HANDLE h_Mutex;
h_Mutex = CreateMutex(NULL, FALSE, "mutex_for_readcount");

// the array of the thread object
HANDLE h_Thread[MAX_THREAD_NUM];
ThreadInfo thread_info[MAX_THREAD_NUM];

readcount = 0; // Initialize readcount
InitializeCriticalSection(&RP_Write);
ifstream inFile;
inFile.open(file);
printf("Reader Priority:/n/n");
while(inFile)
{
// read every writer,reader's information
inFile>>thread_info[n_thread].serial;
inFile>>thread_info[n_thread].entity;
inFile>>thread_info[n_thread].delay;
inFile>>thread_info[n_thread++].persist;
inFile.get();
}
for(int i = 0; i < (int)(n_thread); i++)
{
if(thread_info[i].entity == READER || thread_info[i].entity == 'r')
{
// create reader thread
h_Thread[i] = CreateThread(NULL, 0,
(LPTHREAD_START_ROUTINE)(RP_ReaderThread),
&thread_info[i],
0, &thread_ID);
}
else
{
h_Thread[i] = CreateThread(NULL, 0,
(LPTHREAD_START_ROUTINE)(RP_WriterThread),
&thread_info[i],
0, &thread_ID);
}
}

// wait for all thread to terminate.
wait_for_all = WaitForMultipleObjects(n_thread, h_Thread, TRUE, -1);
printf("All reader and writer have finished operating./n");
}

void WP_ReaderThread(void *p)
{
// execlusive object
HANDLE h_Mutex1;
h_Mutex1 = OpenMutex(MUTEX_ALL_ACCESS, FALSE, "mutex1");
HANDLE h_Mutex2;
h_Mutex2 = OpenMutex(MUTEX_ALL_ACCESS, FALSE, "mutex2");

DWORD wait_for_mutex1; // wait for the mutex1
DWORD wait_for_mutex2;
DWORD m_delay; // latency time
DWORD m_persist; // the time it used for reading the file
int m_serial; // the serial number of the thread
// get information from the parameter
m_serial = ((ThreadInfo *)(p))->serial;
m_delay = (DWORD)(((ThreadInfo *)(p))->delay*INTE_PER_SEC);
m_persist = (DWORD)(((ThreadInfo *)(p))->persist*INTE_PER_SEC);
Sleep(m_delay); // wait for a while

printf("Reader thread %d sents the reading require./n", m_serial);
wait_for_mutex1 = WaitForSingleObject(h_Mutex1, -1);

// enter the reader's critical section
EnterCriticalSection(&cs_Read);

// block execlusive object mutex2, ensure the access,modify to readcount is
// execlusive.
wait_for_mutex2 = WaitForSingleObject(h_Mutex2, -1);
// modify the reader's number
readcount++;
if(readcount == 1)
{
// if it is the first reader, wait for the writer finish
EnterCriticalSection(&cs_Write);
}
ReleaseMutex(h_Mutex2); // release the execlusive signal mutex2
// let other reader enter the critical section
LeaveCriticalSection(&cs_Read);
ReleaseMutex(h_Mutex1);
// read file
printf("Reader thread %d begins to read file./n", m_serial);
// block execlusive object mutex2, ensure the access, modify to readcount
// is execlusive.
wait_for_mutex2 = WaitForSingleObject(h_Mutex2, -1);
readcount--;
if(readcount == 0)
{
// the last reader, wake up writer
LeaveCriticalSection(&cs_Write);
}
ReleaseMutex(h_Mutex2); // release execlusive signal
}

void WP_WriterThread(void *p)
{
DWORD m_delay;
DWORD m_persist;
int m_serial;
DWORD wait_for_mutex3;
HANDLE h_Mutex3;
h_Mutex3 = OpenMutex(MUTEX_ALL_ACCESS, FALSE, "mutex3");

// get information from the parameter
m_serial = ((ThreadInfo *)(p))->serial;
m_delay = (DWORD)(((ThreadInfo *)(p))->delay*INTE_PER_SEC);
m_persist = (DWORD)(((ThreadInfo *)(p))->persist*INTE_PER_SEC);
Sleep(m_delay); // latency wait
printf("Writer thread %d sents the writing require./n", m_serial);

// block execlusive object mutex3, ensure the access,modify to writecount
// is execlusive.
wait_for_mutex3 = WaitForSingleObject(h_Mutex3, -1);
writecount++; // modify the number of writer
if(writecount == 1)
{
// the first writer, wait for the reader finish.
EnterCriticalSection(&cs_Read);
}
ReleaseMutex(h_Mutex3);

// enter the writer critical section
EnterCriticalSection(&cs_Write);

// write the file
printf("Writer thread %d begins to write to the file./n", m_serial);
Sleep(m_persist);

// exit the thread.
printf("Writer thread %d finishing writing to the file./n", m_serial);
// leave the critical section
LeaveCriticalSection(&cs_Write);

wait_for_mutex3 = WaitForSingleObject(h_Mutex3, -1);
writecount--;
if(writecount == 0)
{
// writer finished, reader can read.
LeaveCriticalSection(&cs_Read);
}
ReleaseMutex(h_Mutex3);
}

void WriterPriority(char * file)
{
DWORD n_thread = 0;
DWORD thread_ID;
DWORD wait_for_all;

// execlusive object
HANDLE h_Mutex1;
h_Mutex1 = CreateMutex(NULL, FALSE, "mutex1");
HANDLE h_Mutex2;
h_Mutex2 = CreateMutex(NULL, FALSE, "mutex2");
HANDLE h_Mutex3;
h_Mutex3 = CreateMutex(NULL, FALSE, "mutex3");

// thread object
HANDLE h_Thread[MAX_THREAD_NUM];
ThreadInfo thread_info[MAX_THREAD_NUM];

readcount = 0;
writecount = 0;
InitializeCriticalSection(&cs_Write);
InitializeCriticalSection(&cs_Read);
ifstream inFile;
inFile.open(file);
printf("Writer Priority:/n/n");
while(inFile)
{
inFile>>thread_info[n_thread].serial;
inFile>>thread_info[n_thread].entity;
inFile>>thread_info[n_thread].delay;
inFile>>thread_info[n_thread++].persist;
inFile.get();
}
for(int i = 0; i < (int)(n_thread); i++)
{
if(thread_info[i].entity == READER || thread_info[i].entity == 'r')
{
// create reader thread
h_Thread[i] = CreateThread(NULL, 0,
(LPTHREAD_START_ROUTINE)(WP_ReaderThread), &thread_info[i],
0, &thread_ID);
}
else
{
// create writer thread
h_Thread[i] = CreateThread(NULL, 0,
(LPTHREAD_START_ROUTINE)(WP_WriterThread),
&thread_info[i],
0, &thread_ID);
}
}

wait_for_all = WaitForMultipleObjects(n_thread, h_Thread, TRUE, -1);
printf("All reader and writer have finished operating./n");
}

运行结果:



结果分析:

Writer thread 2 sents the write require.

当写者2发出申请时,有读者1在读文件,所以写者2阻塞。

Reader thread 3 sents the reading require.

Reader thread 3 begins to read file.

读者3发出申请后,立刻得到满足。

读者6和读者7发送请求时已没有读者线程,所以他们被安排在写者线程完成写操作后读文件。

习题:

用P,V操作实现多个生产者-消费者问题。

有兴趣的话可以做一下这个习题,加深对线程,同步及互斥的理解,我将在以后的内容中给出我的想法。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: