295 lines
6.9 KiB
ObjectPascal
295 lines
6.9 KiB
ObjectPascal
{******************************************************************
|
|
|
|
JEDI-VCL Demo
|
|
|
|
Copyright (C) 2002 Project JEDI
|
|
|
|
Original author:
|
|
|
|
Contributor(s):
|
|
|
|
You may retrieve the latest version of this file at the JEDI-JVCL
|
|
home page, located at http://jvcl.sourceforge.net
|
|
|
|
The contents of this file are used with permission, subject to
|
|
the Mozilla Public License Version 1.1 (the "License"); you may
|
|
not use this file except in compliance with the License. You may
|
|
obtain a copy of the License at
|
|
http://www.mozilla.org/MPL/MPL-1_1Final.html
|
|
|
|
Software distributed under the License is distributed on an
|
|
"AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
|
implied. See the License for the specific language governing
|
|
rights and limitations under the License.
|
|
|
|
******************************************************************}
|
|
|
|
unit fPhilosophers;
|
|
|
|
interface
|
|
|
|
uses
|
|
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
|
|
Dialogs, StdCtrls, JvMTThreading, ExtCtrls, ComCtrls,
|
|
JvMtComponents, JvComponent;
|
|
|
|
type
|
|
TPhilosopherState = (psThinking, psHungry, psEating);
|
|
|
|
TPerson = class
|
|
public
|
|
Nr: Integer;
|
|
constructor Create(ANumber: Integer);
|
|
end;
|
|
|
|
TMsg = class(TObject)
|
|
public
|
|
Msg: string;
|
|
constructor Create(AMsg: string);
|
|
end;
|
|
|
|
TfrmDiningPhilosophers = class(TForm)
|
|
PhilosopherManager: TJvMtManager;
|
|
PhilosopherThread: TJvMtThread;
|
|
MonitorSection: TJvMtMonitorSection;
|
|
Memo: TMemo;
|
|
BtnStart: TButton;
|
|
BtnTerminate: TButton;
|
|
PersonBuffer: TJvMtVCLToThread;
|
|
MsgToVCL: TJvMtThreadToVCL;
|
|
PhilLabel1: TLabel;
|
|
PhilLabel2: TLabel;
|
|
PhilLabel3: TLabel;
|
|
PhilLabel4: TLabel;
|
|
PhilLabel5: TLabel;
|
|
Shape1: TShape;
|
|
SpeedBar: TTrackBar;
|
|
LblSpeed: TLabel;
|
|
BtnClose: TButton;
|
|
procedure BtnStartClick(Sender: TObject);
|
|
procedure BtnTerminateClick(Sender: TObject);
|
|
procedure PersonBufferCanWrite(Sender: TObject);
|
|
procedure MsgToVCLCanRead(Sender: TObject);
|
|
procedure FormCreate(Sender: TObject);
|
|
procedure SpeedBarChange(Sender: TObject);
|
|
procedure FormShow(Sender: TObject);
|
|
procedure BtnCloseClick(Sender: TObject);
|
|
procedure PhilosopherThreadExecute(Sender: TJvMtThread;
|
|
MTThread: TJvMtSingleThread);
|
|
private
|
|
{ Private declarations }
|
|
FSpeed: Integer;
|
|
FNrCycle: Integer;
|
|
FState: Array[0..4] of TPhilosopherState;
|
|
procedure SetPhilLabelsEnabled(Value: Boolean);
|
|
procedure TerminatePhilosophers;
|
|
procedure ProcessMsg(M: string);
|
|
procedure WaitRandom;
|
|
public
|
|
{ Public declarations }
|
|
end;
|
|
|
|
var
|
|
frmDiningPhilosophers: TfrmDiningPhilosophers;
|
|
|
|
implementation
|
|
|
|
{$R *.dfm}
|
|
|
|
{ TPerson }
|
|
|
|
constructor TPerson.Create(ANumber: Integer);
|
|
begin
|
|
Nr := ANumber;
|
|
end;
|
|
|
|
{ TMsg }
|
|
|
|
constructor TMsg.Create(AMsg: string);
|
|
begin
|
|
Msg := AMsg;
|
|
end;
|
|
|
|
{ TForm2 }
|
|
|
|
|
|
procedure TfrmDiningPhilosophers.WaitRandom;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
for I := 0 to 5+Random(15) do
|
|
begin
|
|
Sleep(FSpeed);
|
|
CurrentMTThread.CheckTerminate;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmDiningPhilosophers.BtnStartClick(Sender: TObject);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
Memo.Lines.Add('Terminating previous philosophers...');
|
|
TerminatePhilosophers;
|
|
PhilosopherManager.WaitThreads;
|
|
|
|
Memo.Lines.Add('Initiating five new philosophers...');
|
|
|
|
// reset the states
|
|
for I := 0 to 4 do
|
|
FState[I] := psThinking;
|
|
|
|
// make 5 philosophers
|
|
for I := 0 to 4 do
|
|
PhilosopherThread.RunCopy;
|
|
|
|
SetPhilLabelsEnabled(True);
|
|
end;
|
|
|
|
procedure TfrmDiningPhilosophers.BtnTerminateClick(Sender: TObject);
|
|
begin
|
|
Memo.Lines.Add('Terminating all philosophers...');
|
|
TerminatePhilosophers;
|
|
end;
|
|
|
|
procedure TfrmDiningPhilosophers.PersonBufferCanWrite(Sender: TObject);
|
|
begin
|
|
PersonBuffer.Write(TPerson.Create(FNrCycle));
|
|
FNrCycle := (FNrCycle+1) mod 5;
|
|
end;
|
|
|
|
procedure TfrmDiningPhilosophers.ProcessMsg(M: string);
|
|
var
|
|
Nr: Integer;
|
|
Lbl: TLabel;
|
|
begin
|
|
Nr := StrToInt(Copy(M,1,1))+1;
|
|
Lbl:=FindComponent('PhilLabel'+IntToStr(Nr)) as TLabel;
|
|
if Assigned(Lbl) then Lbl.Caption := Copy(M,2,255);
|
|
end;
|
|
|
|
procedure TfrmDiningPhilosophers.MsgToVCLCanRead(Sender: TObject);
|
|
var
|
|
M: TMsg;
|
|
begin
|
|
M := TMsg(MsgToVCL.Read);
|
|
try
|
|
ProcessMsg(M.Msg);
|
|
finally
|
|
M.Free;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmDiningPhilosophers.FormCreate(Sender: TObject);
|
|
begin
|
|
Randomize;
|
|
end;
|
|
|
|
procedure TfrmDiningPhilosophers.TerminatePhilosophers;
|
|
begin
|
|
// terminate any philosphers
|
|
PhilosopherManager.TerminateThreads;
|
|
SetPhilLabelsEnabled(False);
|
|
end;
|
|
|
|
procedure TfrmDiningPhilosophers.SetPhilLabelsEnabled(Value: Boolean);
|
|
begin
|
|
PhilLabel1.Enabled := Value;
|
|
PhilLabel2.Enabled := Value;
|
|
PhilLabel3.Enabled := Value;
|
|
PhilLabel4.Enabled := Value;
|
|
PhilLabel5.Enabled := Value;
|
|
end;
|
|
|
|
procedure TfrmDiningPhilosophers.SpeedBarChange(Sender: TObject);
|
|
begin
|
|
FSpeed := SpeedBar.Position;
|
|
end;
|
|
|
|
procedure TfrmDiningPhilosophers.FormShow(Sender: TObject);
|
|
begin
|
|
FSpeed := SpeedBar.Position;
|
|
end;
|
|
|
|
procedure TfrmDiningPhilosophers.BtnCloseClick(Sender: TObject);
|
|
begin
|
|
Close;
|
|
end;
|
|
|
|
procedure TfrmDiningPhilosophers.PhilosopherThreadExecute(
|
|
Sender: TJvMtThread; MTThread: TJvMtSingleThread);
|
|
procedure Test(Nr: Integer);
|
|
begin
|
|
if (FState[(Nr+4) mod 5] <> psEating) and (FState[Nr] = psHungry) and
|
|
(FState[(Nr+1) mod 5] <> psEating) then
|
|
begin
|
|
FState[Nr] := psEating;
|
|
MonitorSection[Nr].Signal;
|
|
end;
|
|
end;
|
|
|
|
procedure PickupChopsticks(Nr: Integer);
|
|
begin
|
|
MonitorSection.Enter;
|
|
try
|
|
FState[Nr] := psHungry;
|
|
Test(Nr);
|
|
if FState[Nr] <> psEating then
|
|
MonitorSection[Nr].Wait;
|
|
finally
|
|
MonitorSection.Leave;
|
|
end;
|
|
end;
|
|
|
|
procedure PutdownChopsticks(Nr: Integer);
|
|
begin
|
|
MonitorSection.Enter;
|
|
try
|
|
FState[Nr] := psThinking;
|
|
Test((Nr+4) mod 5);
|
|
Test((Nr+1) mod 5);
|
|
finally
|
|
MonitorSection.Leave;
|
|
end;
|
|
end;
|
|
|
|
procedure Msg(S: string);
|
|
begin
|
|
//OutputDebugString(PChar(S));
|
|
MsgToVCL.Write(TMsg.Create(S));
|
|
end;
|
|
|
|
var
|
|
Person: TPerson;
|
|
|
|
begin
|
|
OutputDebugString(PChar('Philosopher is waiting for personality...'));
|
|
Person := PersonBuffer.Read as TPerson;
|
|
try
|
|
Msg(IntToStr(Person.Nr)+' Acquired personality');
|
|
|
|
while True do
|
|
begin
|
|
// philosopher is thinking
|
|
Msg(IntToStr(Person.Nr)+' Thinking');
|
|
WaitRandom;
|
|
|
|
// philosopher is hungry
|
|
Msg(IntToStr(Person.Nr)+' Pickup chopsticks');
|
|
PickupChopsticks(Person.Nr);
|
|
|
|
// philosopher is eating
|
|
Msg(IntToStr(Person.Nr)+' Eating');
|
|
WaitRandom;
|
|
|
|
// philosopher is finished eating
|
|
//Msg(IntToStr(Person.Nr)+' Putdown chopsticks');
|
|
PutdownChopsticks(Person.Nr);
|
|
end;
|
|
|
|
finally
|
|
Person.Free;
|
|
end;
|
|
end;
|
|
|
|
end.
|