# Include <windows. h>
# Include <fstream. h>
# Include <stdio. h>
# Include <string>
# Include <conio. h>
// Define some constants;
// Maximum number of critical zones allowed by this program;
# Define MAX_BUFFER_NUM 10
// Multiplication factor from seconds to microseconds;
# Define INTE_PER_SEC 1000
// The total number of Production and Consumption threads allowed by this program;
# Define MAX_THREAD_NUM 64
// Define a structure to record the parameters of each thread specified in the test file
Struct ThreadInfo
{
Int serial; // thread serial number
Char entity; // whether it is P or C
Double delay; // thread latency
Int thread_request [max_thread_num]; // thread Request queue
Int n_request; // number of requests
};
// Global variable definition
// Declaration of the Critical Area object, used to manage the mutex access of the buffer zone;
Int buffer_critical [max_buffer_num]; // buffer declaration, used to store the product;
Threadinfo thread_info [max_thread_num]; // an array of thread information;
Handle h_thread [max_thread_num]; // array used to store each thread handle;
HANDLE empty_semaphore; // a semaphore;
HANDLE h_mutex; // A mutex;
HANDLE h_Semaphore [MAX_THREAD_NUM]; // The semaphore that the producer allows the consumer to start consumption;
CRITICAL_SECTION PC_Critical [MAX_BUFFER_NUM];
DWORD n_Thread = 0; // the actual number of threads;
DWORD n_Buffer_or_Critical; // number of actual buffers or critical zones;
// Declaration of production consumption and auxiliary functions
Void Produce (void * p );
Void Consume (void * p );
Bool IfInOtherRequest (int );
Int FindProducePositon ();
Int FindBufferPosition (int );
Int main (int argc, char ** argv)
{
// Declare the required variables;
DWORD wait_for_all;
Ifstream inFile;
If (argc! = 2 ){
Printf ("Usage: % s <File>/n", argv [0]);
Return 1;
}
// Initialize the buffer;
For (int I = 0; I <MAX_BUFFER_NUM; I ++)
Buffer_critical [I] =-1;
// Initialize the Request queue of each thread;
For (Int J = 0; j <max_thread_num; j ++ ){
For (int K = 0; k <max_thread_num; k ++)
Thread_info [J]. thread_request [k] =-1;
Thread_info [J]. n_request = 0;
}
// Initialize the critical section;
For (I = 0; I <max_buffer_num; I ++)
Initializecriticalsection (& pc_critical [I]);
// Open the input file and extract thread information according to the specified format;
Infile. Open (argv [1]);
// Obtain the actual number of buffers from the file, that is, the first row of the test file;
InFile> n_Buffer_or_Critical;
InFile. get (); // read the space in the test file and point the file pointer to the next line;
Printf ("input file:/n ");
// The number of buffers obtained by ECHO;
Printf ("% d/n", (int) n_Buffer_or_Critical );
// Extract information of each thread to the corresponding data structure;
While (inFile ){
InFile> Thread_Info [n_Thread]. serial;
InFile> Thread_Info [n_Thread]. entity;
InFile> Thread_Info [n_Thread]. delay;
Char c;
InFile. get (c );
While (c! = '/N '&&! InFile. eof ()){
InFile> Thread_Info [n_Thread]. thread_request [Thread_Info [n_Thread]. n_request ++];
InFile. get (c );
}
N_Thread ++;
}
// Display the thread information obtained by ECHO to check whether the thread information is correct;
For (j = 0; j <(int) n_Thread; j ++ ){
Int Temp_serial = Thread_Info [j]. serial;
Char Temp_entity = Thread_Info [j]. entity;
Double Temp_delay = Thread_Info [j]. delay;
Printf ("/nthread % 2d % c % f", Temp_serial, Temp_entity, Temp_delay );
Int Temp_request = Thread_Info [j]. n_request;
For (int k = 0; k <Temp_request; k ++)
Printf ("% d", Thread_Info [j]. thread_request [k]);
Cout <endl;
}
Printf ("/n ");
// Create several necessary semaphores During Simulation
Empty_semaphore = CreateSemaphore (NULL, n_Buffer_or_Critical, n_Buffer_or_Critical,
"Semaphore_for_empty ");
H_mutex = CreateMutex (NULL, FALSE, "mutex_for_update ");
// The following cycle uses the thread ID to read and write the product of the corresponding production thread.
// Use the synchronous semaphore name;
For (j = 0; j <(int) n_Thread; j ++ ){
Char lp [] = "semaphore_for_produce _";
Int temp = j;
While (temp ){
Char c = (char) (temp % 10 );
Strcat (lp, & c );
Temp/= 10;
}
H_Semaphore [j + 1] = CreateSemaphore (NULL, 0, n_Thread, lp );
}
// Create producer and consumer threads;
For (I = 0; I <(int) n_Thread; I ++ ){
If (Thread_Info [I]. entity = 'P ')
H_Thread [I] = CreateThread (NULL, 0, (LPTHREAD_START_ROUTINE) (Produce ),
& (Thread_Info [I]), 0, NULL );
Else
H_thread [I] = createthread (null, 0, (lpthread_start_routine) (consume ),
& (Thread_info [I]), 0, null );
}
// The main program waits for the action of each thread to end;
Wait_for_all = waitformultipleobjects (n_thread, h_thread, true,-1 );
Printf ("/n/Nall producer and consumer have finished their work./N ");
Printf ("press any key to quit! /N ");
_ Getch ();
Return 0;
}
// Confirm whether there are still consumption requests for the same product that have not been executed;
Bool ifinotherrequest (INT req)
{
For (INT I = 0; I <n_thread; I ++)
For (Int J = 0; j <thread_info [I]. n_request; j ++)
If (thread_info [I]. thread_request [J] = req)
Return true;
Return false;
}
// Locate the available empty buffer zone for product production;
Int findproduceposition ()
{
Int emptyposition;
For (INT I = 0; I <n_buffer_or_critical; I ++)
If (buffer_critical [I] =-1 ){
Emptyposition = I;
// Use the following special value to indicate that the buffer is being written;
Buffer_critical [I] =-2;
Break;
}
Return emptyposition;
}
// Locate the position of the product to be produced by the current producer;
Int findbufferposition (INT propos)
{
Int temppos;
For (INT I = 0; I <n_buffer_or_critical; I ++)
If (buffer_critical [I] = propos ){
Temppos = I;
Break;
}
Return temppos;
}
// Producer Process
Void produce (void * P)
{
// Local variable Declaration;
DWORD wait_for_semaphore, wait_for_mutex, m_delay;
Int m_serial;
// Obtain the thread information;
M_serial = (threadinfo *) (p)-> serial;
M_delay = (DWORD) (threadinfo *) (p)-> delay * inte_per_sec );
Sleep (m_delay );
// Start request Production
Printf ("producer % 2D sends the produce require./N", m_serial );
// Mutually exclusive access to the next blank critical area that can be used for production to achieve mutually exclusive write and write;
Wait_for_mutex = waitforsingleobject (h_mutex,-1 );
// Confirm that the free buffer zone is available for production, and reduce the number of empty locations by 1; used for synchronization between producers and consumers;
// Wait until the consumer process releases the resource;
Wait_for_semaphore = waitforsingleobject (empty_semaphore,-1 );
Int producepos = findproduceposition ();
Releasemutex (h_mutex );
// After the producer obtains its own null position and marks it, the following write operations can be performed concurrently between producers;
// In the core production step, the program uses the producer ID as the product ID to facilitate consumer identification;
Printf ("producer % 2D begin to produce at position % 2D./N", m_serial, producepos );
Buffer_critical [producepos] = m_serial;
Printf ("producer % 2D Finish producing:/N", m_serial );
Printf ("position [% 2D]: % 3d/n", producepos, buffer_critical [producepos]);
// Enable the buffer written by the producer to be used by multiple consumers for read/write synchronization;
ReleaseSemaphore (h_Semaphore [m_serial], n_Thread, NULL );
}
// Consumer Process
Void Consume (void * p)
{
// Local variable Declaration;
DWORD wait_for_semaphore, m_delay;
Int m_serial, m_requestNum; // the serial number of the consumer and the number of requests;
Int m_thread_request [MAX_THREAD_NUM]; // Request queue of the consumption thread;
// Extract the thread information to the local device;
M_serial = (ThreadInfo *) (p)-> serial;
M_delay = (DWORD) (ThreadInfo *) (p)-> delay * INTE_PER_SEC );
M_requestNum = (ThreadInfo *) (p)-> n_request;
For (int I = 0; I <m_requestNum; I ++)
M_thread_request [I] = (ThreadInfo *) (p)-> thread_request [I];
Sleep (m_delay );
// Consume the required products cyclically
For (I = 0; I <m_requestNum; I ++ ){
// Request to consume the next product
Printf ("Consumer % 2d request to consume % 2d product/n", m_serial, m_thread_request [I]);
// If the corresponding producer does not have production, wait; if production is in progress, the number of consumers allowed is-1; read/write synchronization is realized;
Wait_for_semaphore = WaitForSingleObject (h_Semaphore [m_thread_request [I],-1 );
// Query the number of the product to be placed in the buffer zone
Int BufferPos = FindBufferPosition (m_thread_request [I]);
// Start the consumption Processing of a specific buffer. The read and read operations are mutually exclusive in the buffer;
// After entering the critical section, execute the Consumption Action. After completing this request, notify another consumer that the request has been
// Met; and if the corresponding product is used up, it will be processed accordingly; and the interface for corresponding actions will be provided
// Display; this processing refers to clearing the corresponding buffer and adding a semaphore representing the empty buffer;
EnterCriticalSection (& PC_Critical [BufferPos]);
Printf ("Consumer % 2d begin to consume % 2d product/n", m_serial, m_thread_request [I]);
(ThreadInfo *) (p)-> thread_request [I] =-1;
If (! IfInOtherRequest (m_thread_request [I]) {
Buffer_critical [bufferpos] =-1; //-1 indicates that the buffer zone is empty;
Printf ("Consumer % 2D finish consuming % 2D:/N", m_serial, m_thread_request [I]);
Printf ("position [% 2D]: % 3d/n", bufferpos, buffer_critical [bufferpos]);
Releasesemaphore (empty_semaphore, 1, null );
}
Else {
Printf ("Consumer % 2D finish consuming product % 2D/n", m_serial, m_thread_request [I]);
}
// Exit the critical section
Leavecriticalsection (& pc_critical [bufferpos]);
}
}