Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > IT форум > Помощь студентам
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 10.01.2014, 23:01   #1
Иван12354
 
Регистрация: 25.10.2013
Сообщений: 5
По умолчанию Ошибки в задаче о парикмахере в делфи

Извиняюсь если тема уже не актуальная, и находится не там где нужно. У меня есть программка на делфи, но она не совсем корректно работает. Как только запускаю программу клиентов нет в парикмахерской, а парикмахер уже стрижет, его будят и спит. Помогите это исправить. В программе использую семафор и потоки.
Условия задачи такие:
Имеется парикмахерская с двумя дверями и несколькими креслами. Посетители входят в одну дверь и выходят через другую. Парикмахер всю жизнь обслуживает клиентов. Когда клиентов нет, он спит в своем кресле. Когда посетитель приходит в салон и видит спящего парикмахера, он будит его, садится в кресло и спит, пока тот занят стрижкой. Если во время стрижки приходит еще один клиент, он садится в одно из свободных кресел и засыпает. Если свободных мест нет, клиент уходит. После стрижки парикмахер открывает клиенту выходную дверь и закрывает ее за ним. Если есть ожидающие посетители, парикмахер будит одного из них и ждет, пока тот сядет в кресло, после чего стрижет его.


Код программы:

Код:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls;

type
  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
    procedure AddClient;
    procedure DeleteClient;
//    procedure BudClient;
  private
    { Private declarations }
  public
    { Public declarations }
  end;
  Thread1 = class(TThread)
  private
    { Private declarations }
  protected
    procedure Execute; override;
  end;

  Thread2 = class(TThread)
  private
    { Private declarations }
  protected
    procedure Execute; override;
  end;

  Thread3 = class(TThread)
  private
     {Private declarations}
  protected
    procedure Execute; override;
  end;

var
  Form1:TForm1;

  sem1,sem2,sem3:THandle;

  t1:Thread1;
  t2:Thread2;

  t3:Thread3;
  m1:array[1..5] of BOOL;
  m2:array[1..3] of BOOL;
  Panels:array[1..5] of TPanel;
  Barber:array[1..2] of TPanel;

implementation

{$R *.dfm}

procedure TForm1.DeleteClient;
var
  i:Integer;
  res:BOOL;
begin
  res:=false;
  for i:=5 downto 1 do
    begin
      if m1[i]=true then
      begin
        m1[i]:=false;
        res:=true;
        break;
      end;
    end;
  if res then
    begin
      Panels[i].Caption:='Пусто';
    end;
end;

procedure TForm1.AddClient;
var
  i: integer;
  res: bool;
begin
  res:=false;
  for i:=1 to 5 do
    begin
      if m1[i]=false then
        begin
          m1[i]:=true;
          res:=true;
          break;
        end;
    end;
  if res then
    begin
      Panels[i].Caption:='Занято';
    end;
end;

procedure Thread1.Execute;
begin
  while true do
    begin
      WaitForSingleObject(sem1,INFINITE);
      Sleep(random(10)*100+1000);
      Form1.AddClient;
      ReleaseSemaphore(sem2,1,nil);
    end;
end;

procedure Thread2.Execute;
begin
  while true do
    begin
      WaitForSingleObject(sem2,INFINITE);
      Form1.DeleteClient;
      ReleaseSemaphore(sem1,1,nil);
      Barber[1].Caption:='Стрижет';
      Sleep(random(10)*200+500);
      Barber[1].Caption:='Спит';
      Sleep(300);
    end;
end;

 procedure Thread3.Execute;
begin
      WaitForSingleObject(sem2,INFINITE);
      Form1.DeleteClient;
      ReleaseSemaphore(sem1,1,nil);
      Barber[1].Caption:='Будят';

      Sleep(random(10)*200+500);
      Barber[1].Caption:='Будят';
      Sleep(300);
end;

procedure TForm1.FormCreate(Sender: TObject);
var
  i:Integer;
begin
  for i:=1 to 5 do
    begin
      Panels[i]:=TPanel.Create(self);
      Panels[i].Width:=40;
      Panels[i].Height:=40;
      Panels[i].Top:=10;
      Panels[i].Left:=10+42*(i-1);
      Panels[i].Parent := Self;
      Panels[i].Caption:='Пусто';
      Panels[i].Show;
    end;
  for i:=1 to 1 do
    begin
      Barber[i]:=TPanel.Create(self);
      Barber[i].Width:=70;
      Barber[i].Height:=40;
      Barber[i].Top:=120;
      Barber[i].Left:=10+42*(i-1);
      Barber[i].Parent := Self;
      Barber[i].Caption:='Спит';
      Barber[i].Show;
    end;
  sem1:=CreateSemaphore(nil,5,5,nil);
  sem2:=CreateSemaphore(nil,0,5,nil);
  t1:=THread1.Create(false);
  t2:=THread2.Create(false);
  t3:=THread3.Create(false);

end;
end.


________
Код нужно оформлять по правилам:
тегом [CODE]..[/СODE]
(это кнопочка на панели форматирования с решёточкой #)
Не забывайте об этом!

Модератор.

Последний раз редактировалось Serge_Bliznykov; 10.01.2014 в 23:33.
Иван12354 вне форума Ответить с цитированием
Старый 11.01.2014, 16:42   #2
eoln
Старожил
 
Аватар для eoln
 
Регистрация: 26.04.2008
Сообщений: 2,645
По умолчанию

Не совсем верно построен алгоритм.
И ещё, ИМХО, показывать как спят клиенты или как их будят в 3-ем потоке излишне, т.к. это иллюстрация для WaitForSingleObject и ReleaseSemaphore в том потоке, который отвечает за очередь в парикмахерской.
Можно создать всего 2 потока (очередь и парикмахер).
Немного упростив получим следующее
Код:
type
  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
//    procedure BudClient;
  private
    { Private declarations }
  public
    { Public declarations }
  end;
  Thread1 = class(TThread)
  private
    { Private declarations }
  protected
    procedure Execute; override;
    procedure AddClient;
  end;

  Thread2 = class(TThread)
  private
    { Private declarations }
  protected
    procedure Execute; override;
    procedure DeleteClient;
  end;

var
  Form1:TForm1;

  sem1,sem2:THandle;

  t1:Thread1;
  t2:Thread2;

  Panels:array[1..5] of TPanel;
  Barber:array[1..2] of TPanel;

implementation

{$R *.dfm}

procedure Thread2.DeleteClient;
var
  i:Integer;
begin
  for i:=1 to 5 do
      if Panels[i].Caption='Занято' then
      begin
        Panels[i].Caption:='Пусто';
        break;
      end;
end;

procedure Thread1.AddClient;
var
  i: integer;
begin
  for i:=1 to 5 do
      if Panels[i].Caption='Пусто' then
      begin
        Panels[i].Caption:='Занято';
        break;
      end;
end;

procedure Thread1.Execute; //клиенты
begin
  while true do
    begin
      Sleep(random(5000)); //время до прихода следующего клиента
      WaitForSingleObject(sem1,INFINITE);
      Synchronize(AddClient);
      ReleaseSemaphore(sem2,1,nil); //будим цирюльника
      //а если он занят, то засыпаем и своим показываем, чтобы он не засыпал
      //или же сразу проснулся если попробует это сделать
      //а если всё занято, то семафор не увеличится и этот клиент уйдёт
    end;
end;

procedure Thread2.Execute;  //парикмахер
begin
  while true do
    begin
      WaitForSingleObject(sem2,INFINITE); //спим пока не разбудят
      Barber[1].Caption:='Стрижет'; //это тоже надо синхронизировать, но лень )
      Sleep(random(5000));
      Synchronize(DeleteClient);
      ReleaseSemaphore(sem1,1,nil); //освобождаем кресло
      Barber[1].Caption:='Спит'; //это тоже надо синхронизировать, но лень )
      //если поситители ещё есть, то всё равно ложимся спать и сразу же просыпаемся
    end;
end;

procedure TForm1.FormCreate(Sender: TObject);
var
  i:Integer;
begin
  for i:=1 to 5 do
    begin
      Panels[i]:=TPanel.Create(self);
      Panels[i].Width:=40;
      Panels[i].Height:=40;
      Panels[i].Top:=10;
      Panels[i].Left:=10+42*(i-1);
      Panels[i].Parent := Self;
      Panels[i].Caption:='Пусто';
      Panels[i].Show;
    end;
  for i:=1 to 1 do
    begin
      Barber[i]:=TPanel.Create(self);
      Barber[i].Width:=70;
      Barber[i].Height:=40;
      Barber[i].Top:=120;
      Barber[i].Left:=10+42*(i-1);
      Barber[i].Parent := Self;
      Barber[i].Caption:='Спит';
      Barber[i].Show;
    end;
  sem1:=CreateSemaphore(nil,5,5,nil);
  sem2:=CreateSemaphore(nil,0,5,nil);
  t1:=THread1.Create(false);
  t2:=THread2.Create(false);
end;
eoln вне форума Ответить с цитированием
Старый 11.01.2014, 21:15   #3
Иван12354
 
Регистрация: 25.10.2013
Сообщений: 5
По умолчанию

Спасибо за помощь. Подскажите еще как сделать что бы посетители будили парикмахера. Заранее спасибо
Иван12354 вне форума Ответить с цитированием
Старый 11.01.2014, 22:56   #4
eoln
Старожил
 
Аватар для eoln
 
Регистрация: 26.04.2008
Сообщений: 2,645
По умолчанию

ReleaseSemaphore(sem2,1,nil); - вот он будильник парикмахера. Тут даже 5 будильников, которые прикреплены к креслу. Как только посетитель садится на кресло, то сразу включает будильник, даже если парикмахер не спит. Так посетители приманивают цирюльника к себе. После пострижки парикмахер выключает один из будильников. И ложится спать только тогда, когда все кресла опустели и будильники отключены.

Или же нужно визуализировать пробуждение?
UPD, можно примерно так (синхронизировать vcl самостоятельно)
Код:
procedure Thread2.Execute;  //парикмахер
var
  kreslo: integer;
begin
  kreslo := 4;
  while true do
    begin
      WaitForSingleObject(sem2,INFINITE); //спим пока не разбудят
      if kreslo = 4 then begin
         Barber[1].Caption:='Будим';
         Sleep(1000);
      end;
      Barber[1].Caption:='Стрижет'; //это тоже надо синхронизировать, но лень )
      Sleep(random(4000));
      Synchronize(DeleteClient);
      ReleaseSemaphore(sem1,1,@kreslo); //освобождаем кресло
      if kreslo=4 then Barber[1].Caption:='Спит'; //это тоже надо синхронизировать, но лень )
    end;
end;

Последний раз редактировалось eoln; 11.01.2014 в 23:27.
eoln вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Исправте ошибки в задаче саша аврамов Паскаль, Turbo Pascal, PascalABC.NET 1 07.02.2013 23:47
ошибки в задаче. какие? Olgaandsasha Паскаль, Turbo Pascal, PascalABC.NET 1 05.12.2011 08:04
Решите ошибки в задаче! Ivanito Общие вопросы C/C++ 5 16.10.2009 20:55
помогите исправить ошибки в задаче на С++ Wia Помощь студентам 4 14.12.2008 16:09