Eksempel 5. Monitor

Formålet med dette eksempel er at vise, hvordan man kan realisere en monitor i en objekt klasse. Monitoren skal sikre en synkroniseret og udelt adgang til de indkapslede variabler, som i dette tilfælde er en kø og en statuskode. Udover monitoren skal der laves to tråde - en producer og en consumer.

Først dannes et hovedprogram (main thread) på sædvanlig vis. Lav f.eks. et skærmbillede med en Listbox og en Knap, som man kan bruge til at starte consumer tråden med:

Monitoren

Dernæst skal man have lavet sin monitor. Det gøres f.eks. ved i menuen at vælge File | New og derefter vælge Unit. I monitoren skal man samle de funktioner, som skal være beskyttet af en kritisk sektion i de traditionelle tråde. Producer tråden har således brug for en Deposit funktion, som kan gemme en Tekst i køen. Consumer tråden har tilsvarende brug for en Fetch funktion, som kan hente en Tekst i køen.

Udover bufferen har man også brug for en statuskode, som producer tråden kan bruge, når den afsluttes. Consumer tråden kan så se, at de data, der er i køen, er de sidste. Når de er færdigbehandlede, kan consumer tråden også afsluttes.

Statuskoden opdateres med en Terminate funktion. Statuskoden aflæses med funktionen Terminated.

Endelig udstyres monitoren med en Empty funktion, som kan bruges til at teste, om den indkapslede kø er tom. Denne funktion kan man få brug for, når producer tråden er færdig, og man vil sikre sig, at consumer tråden tømmer køen, inden den terminerer.

//---------------------------------------------------------------------------

#ifndef Unit2H

#define Unit2H

#include <syncobjs.hpp>

#include "..\include\Queue.h"

//---------------------------------------------------------------------------

class Monitor

{

private:

TCriticalSection * Lock;

Queue<AnsiString, 5> Buffer;

bool Status;

public:

Monitor();

void Terminate();

bool Terminated();

bool Empty();

void Deposit(AnsiString Input);

AnsiString Fetch();

};

#endif

//---------------------------------------------------------------------------

#include <vcl.h>

#pragma hdrstop

#include "Unit2.h"

//---------------------------------------------------------------------------

#pragma package(smart_init)

Monitor::Monitor()

{

Lock = new TCriticalSection;

Status = false;

}

void Monitor::Terminate()

{

Lock->Acquire();

Status = true;

Lock->Release();

}

bool Monitor::Terminated()

{

bool ReturnStatus;

Lock->Acquire();

ReturnStatus = Status;

Lock->Release();

return ReturnStatus;

}

bool Monitor::Empty()

{

bool ReturnStatus;

Lock->Acquire();

ReturnStatus = Buffer.Empty();

Lock->Release();

return ReturnStatus;

}

 

 

void Monitor::Deposit(AnsiString Input)

{

bool Full;

do

{

Lock->Acquire();

Full = Buffer.Full();

if (!Full)

Buffer.Add(Input);

Lock->Release();

} while (Full);

}

AnsiString Monitor::Fetch()

{

bool Empty;

AnsiString Output;

do

{

Lock->Acquire();

Empty = Buffer.Empty();

if (!Empty)

Output = Buffer.Remove();

Lock->Release();

} while (Empty);

return Output;

}

 

Producer tråden

//---------------------------------------------------------------------------

#include <vcl.h>

#pragma hdrstop

#include "Unit3.h"

#include "Unit2.h"

#pragma package(smart_init)

extern Monitor * m;

//---------------------------------------------------------------------------

__fastcall TThreadProducer::TThreadProducer(bool CreateSuspended)

: TThread(CreateSuspended)

{

}

//---------------------------------------------------------------------------

void __fastcall TThreadProducer::Execute()

{

AnsiString Input;

bool Result;

Result = InputQuery("Producer", "Indtast en tekst", Input);

while (Result)

{

m->Deposit(Input);

Input = "";

Result = InputQuery("Producer", "Indtast en tekst", Input);

}

m->Terminate();

return;

}

//---------------------------------------------------------------------------

 

Consumer tråden

//---------------------------------------------------------------------------

#ifndef Unit4H

#define Unit4H

//---------------------------------------------------------------------------

#include <Classes.hpp>

//---------------------------------------------------------------------------

class TThreadConsumer : public TThread

{

private:

AnsiString Output;

protected:

void __fastcall Execute();

public:

__fastcall TThreadConsumer(bool CreateSuspended);

void __fastcall AddToList();

};

//---------------------------------------------------------------------------

#endif

//---------------------------------------------------------------------------

#include <vcl.h>

#pragma hdrstop

#include "Unit4.h"

#include "Unit2.h"

#include "Unit1.h"

#pragma package(smart_init)

extern Monitor * m;

//---------------------------------------------------------------------------

__fastcall TThreadConsumer::TThreadConsumer(bool CreateSuspended)

: TThread(CreateSuspended)

{

}

void __fastcall TThreadConsumer::AddToList()

{

Form1->ListBox1->Items->Add(Output);

}

//---------------------------------------------------------------------------

void __fastcall TThreadConsumer::Execute()

{

while (!m->Terminated() || !m->Empty())

{

Output = m->Fetch();

Synchronize(AddToList);

}

return;

}