Тема: «Взаємодія між потоками»
Мета: Засвоїти поняття «процесів» та «потоків» як основних компонентів сучасних операційних систем. Здобути навики створення, керування та знищення «процесів» та «потоків» в операційній системі Windows.
Завдання:
Відповідно до варіанту (таблиця) модифікувати програму так, щоб замінити об’єкти синхронізації заданого числа потоків
Таблиця – Варіанти завдань
Системнийвиклик
Варіант
5
Critical Section
4
Mutex
3
Semaphores
Вікно програми результату дослідження стандартної програми:
Текст модифікованої програми:
#include "stdafx.h"
#include "EvryThng.h"
#include <time.h>
#include <stdlib.h>
#include <locale.h>
#define DATA_SIZE 256
typedef struct msg_block_tag { /* Message block */
volatile DWORD f_ready, f_stop;
/* ready state flag, stop flag */
volatile DWORD sequence; /* Message block sequence number */
volatile DWORD nCons, nLost;
short number;
time_t timestamp;
CRITICAL_SECTION mguard; /* Guard the message block structure */
HANDLE hMutex;
DWORD checksum; /* Message contents checksum */
DWORD data[DATA_SIZE]; /* Message Contents */
} MSG_BLOCK;
/* One of the following conditions holds for the message block */
/* 1) !f_ready || f_stop */
/* nothing is assured about the data OR */
/* 2) f_ready && data is valid */
/* && checksum and timestamp are valid */
/* Also, at all times, 0 <= nLost + nCons <= sequence */
/* Single message block, ready to fill with a new message */
MSG_BLOCK mblock = { 0, 0, 0, 0, 0, 0 };
unsigned int WINAPI produce (void *);
unsigned int WINAPI consume (void *);
unsigned int WINAPI _NULL_ (void *);
unsigned int WINAPI _new_ (void *);
void MessageFill (MSG_BLOCK *);
void MessageDisplay (MSG_BLOCK *);
DWORD _tmain (DWORD argc, LPTSTR argv[])
{
unsigned int Status, ThId;
HANDLE produce_h, consume_h, _null_h,_new_h;
/* Initialize the message block CRITICAL SECTION */
InitializeCriticalSection (&mblock.mguard);
mblock.number=1;
printf("==============[ SYNCHRONIZATION CRITICAL SECTION]===============\n");
/* Create the two threads */
produce_h = (HANDLE)_beginthreadex (NULL, 0, produce, NULL, 0, &ThId);
if (produce_h == NULL)
printf("Cannot create producer thread");
consume_h = (HANDLE)_beginthreadex (NULL, 0, consume, NULL, 0, &ThId);
if (consume_h == NULL)
printf("Cannot create consumer thread");
_null_h = (HANDLE)_beginthreadex (NULL, 0, _NULL_, NULL, 0, &ThId);
if (_null_h == NULL)
printf("Cannot create _NULL_ thread");
_new_h = (HANDLE)_beginthreadex (NULL, 0, _new_, NULL, 0, &ThId);
if (_new_h == NULL)
printf("Cannot create _new_ thread");
/* Wait for the producer and consumer to complete */
Status = WaitForSingleObject (consume_h, INFINITE);
if (Status != WAIT_OBJECT_0)
printf("Failed waiting for consumer thread");
Status = WaitForSingleObject (produce_h, INFINITE);
if (Status != WAIT_OBJECT_0)
printf("Failed waiting for producer thread");
Status = WaitForSingleObject (_null_h, INFINITE);
if (Status != WAIT_OBJECT_0)
printf("Failed waiting for null thread");
Status = WaitForSingleObject (_new_h, INFINITE);
if (Status != WAIT_OBJECT_0)
printf("Failed waiting for _new_ thread");
DeleteCriticalSection (&mblock.mguard);
_tprintf (_T("Producer, consumer, null and new threads have terminated\n"));
_tprintf (_T("Messages produced: %d, Consumed: %d, Known Lost: %d\n"),
mblock.sequence, mblock.nCons, mblock.nLost);
Sleep(1000);
printf("==============[ SYNCRNIZATION MUTEX ]===============\n");
mblock.nCons =0;
mblock.f_ready =0;
mblock.nLost =0;
mblock.sequence =0;
mblock.f_stop = 0;
mblock.number=2;
mblock.hMutex = CreateMutex( NULL, FALSE, NULL );
produce_h = NULL;
consume_h = NULL;
produce_h = (HANDLE)_beginthreadex (NULL, 0, produce, NULL, 0, &ThId);
if (produce_h == NULL)
printf("Cannot create producer thread");
consume_h =(HANDLE)_beginthreadex (NULL, 0, consume, NULL, 0, &ThId);
if (consume_h == NULL)
printf("Cannot create consumer thread");
_null_h = (HANDLE)_beginthreadex (NULL, 0, _NULL_, NULL, 0, &ThId);
if (_null_h == NULL)
printf("Cannot create _NULL_ thread");
Status = WaitForSingleObject (consume_h, INFINITE);
if (Status != WAIT_OBJECT_0)
printf("Failed waiting for consumer thread");
Status = WaitForSingleObject (produce_h, INFINITE);
if (Status != WAIT_OBJECT_0)
printf("Failed waiting for producer thread");
Status = WaitForSingleObject (_null_h, INFINITE);
if (Status != WAIT_OBJECT_0)
printf("Failed waiting for null thread");
_tprintf (_T("Producer, consumer and null threads have terminated\n"));
_tprintf (_T("Messages produced: %d, Consumed: %d, Known Lost: %d\n"),
mblock.sequence, mblock.nCons, mblock.nLost);
system("pause");
return 0;
}
unsigned int WINAPI _new_ (void *arg)
{
while (!mblock.f_stop) {
Sleep(1000);
EnterCriticalSection (&mblock.mguard);
__try {
if (!mblock.f_stop) {
mblock.sequence=mblock.sequence+100;
}}
__finally { LeaveCriticalSection (&mblock.mguard); }
}
return 0;
}
unsigned int WINAPI _NULL_ (void *arg)
{
while (!mblock.f_stop) {
Sleep(7000);
if(mblock.number==1)
{
EnterCriticalSection (&mblock.mguard);
__try {
if (!mblock.f_stop) {
mblock.nCons =0;
mblock.f_ready =0;
mblock.nLost =0;
mblock.sequence =0;
mblock.f_stop = 0;
printf("Vsi pokaznuku obnuleni\n");
}}
__finally { LeaveCriticalSection (&mblock.mguard); }
}
else
{
WaitForSingleObject(mblock.hMutex,INFINITE);
__try {
if (!mblock.f_stop) {
mblock.nCons =0;
mblock.f_ready =0;
mblock.nLost =0;
mblock.sequence =0;
mblock.f_stop = 0;
printf("Vsi pokaznuku obnuleni\n");
}
} __finally { ReleaseMutex(mblock.hMutex); }
}}
return 0;
}
unsigned int WINAPI produce (void *arg)
/* Producer thread - Create new messages at random intervals */
{
srand ((DWORD)time(NULL)); /* Seed the random # generator */
while (!mblock.f_stop) {
/* Random Delay */
Sleep(rand()/100);
/* Get the buffer, fill it */
if(mblock.number==1)
{
EnterCriticalSection (&mblock.mguard);
__try {
if (!mblock.f_stop) {
mblock.f_ready = 0;
MessageFill (&mblock);
mblock.f_ready = 1;
mblock.sequence++;
}}
__finally { LeaveCriticalSection (&mblock.mguard); }
}
else
{
WaitForSingleObject(mblock.hMutex,INFINITE);
__try{
if (!mblock.f_stop) {
mblock.f_ready = 0;
MessageFill (&mblock);
mblock.f_ready = 1;
mblock.sequence++;
}}
__finally {ReleaseMutex(mblock.hMutex);}
}
}
return 0;
}
unsigned int WINAPI consume (void *arg)
{
DWORD ShutDown = 0;
int Shut = 0;
CHAR command,extra;
/* Consume the NEXT message when prompted by the user */
while (!ShutDown) { /* This is the only thread accessing stdin, stdout */
_tprintf (_T("\n**Enter 'c' for consume; 's' to stop: "));
scanf ("%c%c", &command,&extra);
if(mblock.number==1)
{
if (command == 's') {
EnterCriticalSection (&mblock.mguard);
ShutDown = mblock.f_stop = 1;
LeaveCriticalSection (&mblock.mguard);
} else if (command == 'c') { /* Get a new buffer to consume */
EnterCriticalSection (&mblock.mguard);
__try {
if (mblock.f_ready == 0)
_tprintf (_T("No new messages. Try again later\n"));
else {
MessageDisplay (&mblock);
mblock.nCons++;
mblock.nLost = mblock.sequence - mblock.nCons;
mblock.f_ready = 0; /* No new messages are ready */
}
}
__finally { LeaveCriticalSection (&mblock.mguard); }
} else {
_tprintf (_T("Illegal command. Try again.\n"));
}
}else
{
if (command == 's') {
WaitForSingleObject(mblock.hMutex,INFINITE);
ShutDown = mblock.f_stop = 1;
ReleaseMutex(mblock.hMutex);
} else if (command == 'c') { /* Get a new buffer to consume */
WaitForSingleObject(mblock.hMutex,INFINITE);
__try {
if (mblock.f_ready == 0)
_tprintf (_T("No new messages. Try again later\n"));
else {
MessageDisplay (&mblock);
mblock.nCons++;
mblock.nLost = mblock.sequence - mblock.nCons;
mblock.f_ready = 0; /* No new messages are ready */
}
}
__finally {ReleaseMutex(mblock.hMutex); }
} else {
_tprintf (_T("Illegal command. Try again.\n"));
}}
}
extra = 'c';
return 0;
}
void MessageFill (MSG_BLOCK *mblock)
{
/* Fill the message buffer, and include checksum and timestamp */
/* This function is called from the producer thread while it */
/* owns the message block mutex */
DWORD i;
mblock->checksum = 0;
for (i = 0; i < DATA_SIZE; i++) {
mblock->data[i] = rand();
mblock->checksum ^= mblock->data[i];
}
mblock->timestamp = time(NULL);
return;
}
void MessageDisplay (MSG_BLOCK *mblock)
{
/* Display message buffer, timestamp, and validate checksum */
/* This function is called from the consumer thread while it */
/* owns the message block mutex */
DWORD i, tcheck = 0;
for (i = 0; i < DATA_SIZE; i++)
tcheck ^= mblock->data[i];
_tprintf (_T("\nMessage number %d generated at: %s"),
mblock->sequence, _tctime (&(mblock->timestamp)));
_tprintf (_T("First and last entries: %x %x\n"),
mblock->data[0], mblock->data[DATA_SIZE-1]);
if (tcheck == mblock->checksum)
_tprintf (_T("GOOD ->Checksum was validated.\n"));
else
_tprintf (_T("BAD ->Checksum failed. message was corrupted\n"));
return;
}
Вікно програми результату:
Висновок: На даній лабораторній роботі я засвоїла поняття паралельного виконання «потоків» та освоїла засоби їх синхронізації. Здобула навики синхронізації «потоків» при обробці спільних даних та доступу до ресурсів в операційній системі Windows.