Форум по Delphi программированию



Вернуться   Форум по Delphi программированию > Все о Delphi > [ "Начинающим" ]
Ник
Пароль
Регистрация <<         Правила форума         >> FAQ Пользователи Календарь Поиск Сообщения за сегодня Все разделы прочитаны

Ответ
 
Опции темы Поиск в этой теме Опции просмотра
  #1  
Старый 30.07.2022, 19:28
arktik arktik вне форума
Прохожий
 
Регистрация: 30.07.2022
Сообщения: 2
Версия Delphi: Delphi 7
Репутация: 10
По умолчанию Класс и поток

Прошу помощи как начинающий.

Ниже выкладываю обобщенные фрагменты из программы.
Есть класс TCSyn и поток MyThread. В потоке выполняется процедура VaChar.
Скажу сразу программа компилируется без ошибок и выполняется. Но...
Но когда запускается поток в процедуре VaChar при выполнении Count:= Count+1; происходит ошибка и процесс останавливается. Похоже, что поток не видит переменных описанных в классе TCSyn. Прошу подсказать как исправить это и что делал не правильно.

Код:
TCSyn = class(TComponent)  //TComponent
  Public
   
    inp          : Tinp;          
    FString    : String;         Сообщение
    Count      : integer;
    Tek          : Double;        
    TimeTek   : Double;        

    Constructor Create(AOwner:TComponent);override;     
    Destructor  Destroy; override;                         
   

    procedure VaChar;
   
  Protected
 
  Private

 End;
-------------------------------------
 type
 MyThread=class(TThread)
 private{private declaration}
  
    pser:  TCSyn;

 protected
 procedure execute;override;
 public

 end;

 var MyThr: MyThread;
-------------------------------------------------------------------------
procedure MyThread.execute;
 var S: string; i:integer;
begin

             Synchronize(pser.VaChar);
 
end;
------------------------------------------------------------------------
procedure TCSyn.VaChar;
var S:String; 
begin


  Count:= Count+1;     


end;
Админ: Пользуемся тегами при оформлении кода!
Ответить с цитированием
  #2  
Старый 30.07.2022, 21:31
lmikle lmikle вне форума
Модератор
 
Регистрация: 17.04.2008
Сообщения: 7,801
Версия Delphi: 7, XE3, 10.2
Репутация: 49089
По умолчанию

1. А тебе точно нужно класс "рожать" от TComponent? Тут я даже не знаю как оно будет работать в потоке, вроде проблем быть не должно, но я бы все-таки в потоке с визуальными компонентами не связывался.
2. А ты уверен, что происходит ошибка? Вообще, по твоему коду процедура потока выполняется 1 раз и потом поток завершается.
3. Ну и, надебсь, ты же создаешь экземпляр TCSyn в конструкторе потока? Просто не указал данный код в примере...
Ответить с цитированием
  #3  
Старый 31.07.2022, 16:50
arktik arktik вне форума
Прохожий
 
Регистрация: 30.07.2022
Сообщения: 2
Версия Delphi: Delphi 7
Репутация: 10
По умолчанию

Цитата:
Сообщение от lmikle
1. А тебе точно нужно класс "рожать" от TComponent? Тут я даже не знаю как оно будет работать в потоке, вроде проблем быть не должно, но я бы все-таки в потоке с визуальными компонентами не связывался.
2. А ты уверен, что происходит ошибка? Вообще, по твоему коду процедура потока выполняется 1 раз и потом поток завершается.
3. Ну и, надебсь, ты же создаешь экземпляр TCSyn в конструкторе потока? Просто не указал данный код в примере...

1 Класс рожать надо, хуже того он рожден до меня другим разработчиком, программа дорабатывается и переделывается мной не столь опытным. Хотелось бы ломать по минимуму.
Поток работает, скажу больше, в примере не все выложено, но в процедуре
execute предварительно читаются два сом порта, а дальнейшая обработка должна производится в VaChar используя данные класса.
2 Ошибка точно происходит и поток выполняется не один раз.
3 Да надо создать экземпляр TCSyn.
pser := TCSyn.Create(nil);
Вот только где? В процедуре execute? Или писать что-то новое? И как потом связать? Вообщем опыта мало, вопросов много.

PS. Подскажите,пожалуйста, как пользоваться тегами.
Ответить с цитированием
  #4  
Старый 31.07.2022, 20:46
lmikle lmikle вне форума
Модератор
 
Регистрация: 17.04.2008
Сообщения: 7,801
Версия Delphi: 7, XE3, 10.2
Репутация: 49089
По умолчанию

1. Не факт, что предыдущий разраб был хорошим.
Тут вопрос не в том, надо ли "рожать" класс, а в том - от какого предка.
Походу надо смотреть весь код, что бы понять, надо ли его рожать от TComponent или все-таки ничего из TComponent не используется и он нафиг не нужен и можно обойтись TObject.
2. Опять же, значит ты не предоставил правильный код. Или имеется в виду, что поток запускается несколько раз? Тут без некоторых важных частей кода не поймешь как оно устроенно. Предоставленный тобой пример может не отражать реальную структуру. Вообще, я бы для начала просто "завернул" бы весь код Execute в Try..Except и залогировал бы появляющуюся ошибку, что бы понять что же там происходит.
3. Я бы, навеоное, создавал его в конструкторе потока. Ну и в деструкторе уничтожал бы.
4. Засовывать ВСЮ обработку данных в Synchronize "не есть гут". Это блокирует основной поток приложения. Synchronize надо использовать только когда идет обращение к объектам главного потока.

PS. Включи расширенный режим редактирования сообщения. Там есть готоыве кнопочки для вставки тегов. Вообще, тут в основном используется 2 тега - code и quote (в кв. скобках, закрывающий тег имеет слеш перед именем).
Ответить с цитированием
  #5  
Старый 03.08.2022, 00:11
lmikle lmikle вне форума
Модератор
 
Регистрация: 17.04.2008
Сообщения: 7,801
Версия Delphi: 7, XE3, 10.2
Репутация: 49089
По умолчанию

Кстати, не знаю какая ошибка у тебя вылетает... Сделал пример на основе твоего кода (пришлось кое-что добавить, что бы было красиво), но все работает:
Код:
unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;

type
  TCSyn = class;
  TMyThread = class;

  TForm1 = class(TForm)
    btStartThread: TButton;
    btReadCount: TButton;
    procedure FormCreate(Sender: TObject);
    procedure btStartThreadClick(Sender: TObject);
    procedure btReadCountClick(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    { Private declarations }
    FMyThread : TMyThread;
  public
    { Public declarations }
  end;

  TCSyn = class(TComponent)
  public
    Count      : integer;
    constructor Create(AOwner:TComponent); override;
    destructor  Destroy; override;
    procedure VaChar;
  end;

  TMyThread = class(TThread)
  private
    pser:  TCSyn;
    FDoWork : Boolean;
  protected
    procedure Execute; override;
  public
    constructor Create(CreateSuspended : Boolean); virtual;
    destructor Destroy; override;
    function GetCount : Integer;
    procedure DoWork;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

constructor TCSyn.Create(AOwner:TComponent);
begin
  inherited;
  Count := 0;
end;

destructor  TCSyn.Destroy;
begin
  inherited;
end;

procedure TCSyn.VaChar;
begin
  Count := Count + 1;
end;

constructor TMyThread.Create(CreateSuspended : Boolean);
begin
  inherited Create(CreateSuspended);
  FDoWork := False;
  pser := TCSyn.Create(Nil);
end;

destructor TMyThread.Destroy;
begin
  pser.Free;
end;

procedure TMyThread.Execute;
begin
  While Not Terminated Do
    Begin
      If FDoWork Then
        Begin
          FDoWork := False;
          Synchronize(pser.VaChar);
        End;
      Sleep(100);
    End;
end;

function TMyThread.GetCount : Integer;
begin
  Result := pser.Count;
end;

procedure TMyThread.DoWork;
begin
  FDoWork := True;
end;

procedure TForm1.btReadCountClick(Sender: TObject);
begin
  If Not Assigned(FMyThread)
    Then MessageDlg('Thread object is not created. Please click "Start Thread" button first',mtError,[mbOk],0)
    Else ShowMessage(Format('Count = %d',[FMyThread.GetCount]));
end;

procedure TForm1.btStartThreadClick(Sender: TObject);
begin
  If Not Assigned(FMyThread)
    Then FMyThread := TMyThread.Create(False)
    Else FMyThread.DoWork;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  FMyThread := Nil;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  If Assigned(FMyThread) Then
    Begin
      FMyThread.Terminate;
      FMyThread.WaitFor;
      FMyThread.Free;
    End;
end;

end.

Да, для реального кода надо будет еще обложиться критическими секциями, что бы не получалось запустить обработку в потоке, если она уже идет. Или вообще лучше сделать очередь заданий, помещать новые задания туда, а поток сам будет от туда их забирать (опять же обложившись критическими секциями). Но в таком простом варианте все работает нормально. Никаких ошибок не вылетает.

ЗЫ. Все делано на 10.2, но думаю, что на других версиях все будет ровно так же.

Последний раз редактировалось lmikle, 03.08.2022 в 00:16.
Ответить с цитированием
Ответ



Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск
Опции просмотра

Ваши права в разделе
Вы не можете создавать темы
Вы не можете отвечать на сообщения
Вы не можете прикреплять файлы
Вы не можете редактировать сообщения

BB-коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.
Быстрый переход


Часовой пояс GMT +3, время: 12:03.


 

Сайт

Форум

FAQ

RSS лента

Прочее

 

Copyright © Форум "Delphi Sources" by BrokenByte Software, 2004-2021

ВКонтакте   Facebook   Twitter   Ссылка на Telegram