Міністерство освіти і науки
Національний університет “Львівська політехніка”
Кафедра ЕОМ
/
Звіт
з лабораторної роботи № 2
з дисципліни: “Системне програмне забезпечення”
на тему: “Взаємодія між потоками”
Мета лабораторної роботи
Засвоїти поняття паралельного виконання «потоків» та освоїти засоби їх синхронізації. Здобути навики синхронізації «потоків» при обробці спільних даних та доступу до ресурсів в операційній системі Windows.
Теоретичні відомості
Windows надає чотири об’єкти, призначені для синхронізації потоків і процесів. Три з них — мютекси, семафори і події — є об’єктами ядра, що мають дескриптори. Події використовуються також для інших цілей, наприклад, для асинхронного уведення-виведення.
Спочатку розглянемо четвертий об’єкт, а саме, об’єкт критичної ділянки коду CRITICAL_SECTION. Через простоту і продуктивність, об’єктам критичних ділянок коду надається перевага, якщо їх можливостей достатньо для того, щоб задовольнити вимоги програміста.
Завдання
1. Дослідити роботу програми в середовищі Visual Studio, що демонструє використання об’єктів критичних ділянок коду та приведена нижче.
2. Відповідно до варіанту (таблиця) модифікувати програму так, щоб замінити об’єкти синхронізації заданого числа потоків
Системнийвиклик
Варіант
1
2
3
4
5
6
7
8
9
10
Critical Section
2
2
3
3
4
2
2
3
3
4
Mutex
2
3
2
4
3
Semaphores
2
3
2
4
3
3. Проаналізувати та пояснити вміст дисплею після завершення програми.
Код програми
#define _CRT_SECURE_NO_WARNINGS
#include <Windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <process.h>
#include <conio.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;
time_t timestamp;
//CRITICAL_SECTION mguard; /* Guard the message block structure */
HANDLE mutex;
int produceThreadNum;
DWORD checksum; /* Message contents checksum */
DWORD data[DATA_SIZE]; /* Message Contents */
} MSG_BLOCK;
MSG_BLOCK mblock = { 0, 0, 0, 0, 0 };
unsigned __stdcall produce(void *);
unsigned __stdcall consume(void *);
void MessageFill(MSG_BLOCK *);
void MessageDisplay(MSG_BLOCK *);
DWORD main(DWORD argc, LPTSTR argv[])
{
DWORD Status, ThId;
HANDLE produce_h, produce_h1, consume_h;
//InitializeCriticalSection(&mblock.mguard);
mblock.mutex = CreateMutex(NULL, FALSE, NULL);
produce_h = (HANDLE)_beginthreadex(NULL, 0, produce, (void *)1, 0, (unsigned *)&ThId);
if (produce_h == NULL)
{
printf("Cannot create producer thread");
}
produce_h1 = (HANDLE)_beginthreadex(NULL, 0, produce, (void *)2, 0, (unsigned *)&ThId);
if (produce_h1 == NULL)
{
printf("Cannot create producer thread");
}
consume_h = (HANDLE)_beginthreadex(NULL, 0, consume, NULL, 0, (unsigned *)&ThId);
if (consume_h == NULL)
{
printf("Cannot create consumer 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(produce_h1, INFINITE);
if (Status != WAIT_OBJECT_0)
{
printf("Failed waiting for producer thread");
}
//DeleteCriticalSection(&mblock.mguard);
CloseHandle(mblock.mutex);
printf("Producer and consumer threads have terminated\n");
printf("Messages produced: %d, Consumed: %d, Known Lost: %d\n", mblock.sequence, mblock.nCons, mblock.nLost);
_getch();
return 0;
}
unsigned __stdcall produce(void *arg)
{
srand((DWORD)time(NULL)); /* Seed the random # generator */
while (!mblock.f_stop)
{
Sleep(rand() / 100);
//EnterCriticalSection(&mblock.mguard);
WaitForSingleObject(mblock.mutex, INFINITE);
__try
{
if (!mblock.f_stop)
{
mblock.f_ready = 0;
MessageFill(&mblock);
mblock.produceThreadNum = (int)arg;
mblock.f_ready = 1;
mblock.sequence++;
}
}
__finally
{
//LeaveCriticalSection(&mblock.mguard);
ReleaseMutex(mblock.mutex);
}
}
return 0;
}
unsigned __stdcall consume(void *arg)
{
DWORD ShutDown = 0;
CHAR command, extra;
while (!ShutDown)
{ /* This is the only thread accessing stdin, stdout */
printf("\n**Enter 'c' for consume; 's' to stop: ");
scanf("%c%c", &command, &extra);
if (command == 's')
{
//EnterCriticalSection(&mblock.mguard);
WaitForSingleObject(mblock.mutex, INFINITE);
ShutDown = mblock.f_stop = 1;
//LeaveCriticalSection(&mblock.mguard);
ReleaseMutex(mblock.mutex);
}
else if (command == 'c')
{ /* Get a new buffer to consume */
//EnterCriticalSection(&mblock.mguard);
WaitForSingleObject(mblock.mutex, INFINITE);
__try
{
if (mblock.f_ready == 0)
{
printf("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);
ReleaseMutex(mblock.mutex);
}
}
else
{
printf("Illegal command. Try again.\n");
}
}
return 0;
}
void MessageFill(MSG_BLOCK *mblock)
{
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);
}
void MessageDisplay(MSG_BLOCK *mblock)
{
DWORD i, tcheck = 0;
for (i = 0; i < DATA_SIZE; i++)
{
tcheck ^= mblock->data[i];
}
printf("\nMessage number %d generated at: %s", mblock->sequence, ctime(&mblock->timestamp));
printf("Message from produce thread number %d\n", mblock->produceThreadNum);
printf("First and last entries: %x %x\n", mblock->data[0], mblock->data[DATA_SIZE - 1]);
if (tcheck == mblock->checksum)
{
printf("GOOD ->Checksum was validated.\n");
}
else
{
printf("BAD ->Checksum failed. message was corrupted\n");
}
}
Результат виконання програми
/
Висновок
На лабораторній роботі я засвоїв поняття паралельного виконання «потоків» та освоїв засоби їх синхронізації, здобув навики синхронізації «потоків» при обробці спільних даних та доступу до ресурсів в операційній системі Windows.