Internship environment:
Windows XP + VC 6.0
Internship objectives:
Create a console process in Windows XP, which should contain n threads. Use the n threads to represent n readers or writers. Each thread performs read/write operations according to the requirements of the corresponding test data file (described later. The semaphore mechanism is used to implement reader-first and writer-first issues respectively.
Restrictions on reader-writer problems (including Reader-first and writer-first ):
1) Write-write mutex, that is, two writers cannot perform write operations at the same time.
2) read-write mutex, that is, one thread cannot read at the same time, while the other thread is writing.
3) read-read mutex, that is, one or more readers can read.
Additional restrictions on reader priority: If a reader applies for a read operation and another reader is performing the read operation, the reader can directly start the read operation.
Additional restrictions on Writer Priority: If a reader requests a read operation and another writer is waiting to access the shared resources, the reader must wait until no writer is waiting for the read operation to start.
The following is an example of a test data file:
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
Program code:
// 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 ");
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 ");
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 ");
}
Running result:
Result Analysis:
Writer thread 2 sents the write require.
When writer 2 sends an application, reader 1 reads the file, so writer 2 is blocked.
Reader thread 3 sents the reading require.
Reader thread 3 begins to read file.
Reader 3 is satisfied immediately after the application is submitted.
Reader 6 and reader 7 have no reader thread when sending the request, so they are arranged to read the file after the writer thread completes the write operation.
Exercise:
Use the P and V Operations to implement multiple producer-consumer problems.
If you are interested, you can do this exercise to deepen your understanding of threads, synchronization, and mutex. I will give my thoughts in future content.