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

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

Вернуться   Форум программистов > Delphi программирование > Общие вопросы Delphi
Регистрация

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

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

Ответ
 
Опции темы Поиск в этой теме
Старый 29.03.2011, 23:10   #1
RobSys
Пользователь
 
Регистрация: 12.10.2010
Сообщений: 19
По умолчанию Потоки и StringGrid

Здравствуйте. Извиняюсь, если данную тему надо было писать в раздел WIN API, а не сюда.

Задача состоит в следующем в одном потоке ArTheads[0] построчно заполняюю StrGr_Data. Затем подсчитываю срдеене арифметическое строки и вношу его в StrGr_SumData другим потоком ArTheads[1]. Синхронизация потоков идет с использованием объекта события E2.

Код:
unit kom_SPPO_THREAD;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, Grids, SyncObjs;

type
  TMainForm = class(TForm)
    StrGr_Data: TStringGrid;
    StrGr_SumData: TStringGrid;
    But_Calculate: TButton;
    procedure FormCreate(Sender: TObject);
    procedure But_CalculateClick(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  MainForm: TMainForm;

implementation

{$R *.dfm}

type
  TMyThread = class(TThread)
  private
    StrGr: TStringGrid;
  protected
    constructor Create (SGr: TStringGrid);
    procedure Execute; override;
    procedure WriteData (i, j: integer);
  end;

var
  E1, E2: TEvent;
  ArThreads: array [0..1] of TMyThread;
  N: integer;
  ArNum: array [1..12,1..4] of real;


constructor TMyThread.Create (SGr: TStringGrid);
begin
  Inherited Create(false);
  StrGr:=SGr;
end;


procedure TMyThread.WriteData (i, j: integer);
begin
  if j<>4 then
  StrGr.Cells[j,i]:=FloatToStr(ArNum[i,j])
  else
  StrGr.Cells[1,i]:=FloatToStr(ArNum[i,j])
end;


procedure TMyThread.Execute;
var
  i, j: integer;
begin
  for i:=1 to 12 do
      begin
        //E1.WaitFor(Infinite);

        E2.ResetEvent;
          ArNum[i,1]:=i;
          sleep(1000);
          WriteData(i,1);

          ArNum[i,2]:=i+1;
          sleep(1000);
          WriteData(i,2);

          ArNum[i,3]:=i+2;
          sleep(1000);
          WriteData(i,3);

          ArNum[i,4]:=0;
          for j:=1 to 3 do
              ArNum[i,4]:=ArNum[i,4]+StrToFloat(StrGr.Cells[j,i]);
          ArNum[i,4]:=ArNum[i,4]/3;

        E2.SetEvent;
        E2.WaitFor(Infinite);

        //E1.ResetEvent;
        WriteData(i,4);
        //E1.SetEvent;
      end;
end;

procedure TMainForm.FormCreate(Sender: TObject);
var
  i: integer;
begin
  N:=StrGr_Data.RowCount;
  StrGr_SumData.RowCount:=N;
  for i:=1 to StrGr_Data.ColCount do
      StrGr_Data.Cells[i,0]:='Human #'+IntToStr(i);
  StrGr_SumData.Cells[1,0]:='Mean Inc:';
  for i:=1 to N-2 do
      begin
        StrGr_Data.Cells[0,i]:=IntToStr(i);
        StrGr_SumData.Cells[0,i]:=IntToStr(i);
      end;
  StrGr_Data.Cells[0,N-1]:='Sum:';
  StrGr_SumData.Cells[0,N-1]:='Sum:';

  E1:=TEvent.Create(nil,true,true,'');
  E2:=TEvent.Create(nil,true,false,'');
end;

procedure TMainForm.But_CalculateClick(Sender: TObject);
begin
  ArThreads[0]:=TMyThread.Create(StrGr_Data);
  ArThreads[1]:=TMyThread.Create(StrGr_SumData);
end;

end.
Проблема в следующем: первый столбец StrGr_Data и StrGr_SumData заполняется одновременно и в том случае, когда начинается и заполнение StrGr_Data и после того, как вносится среднее арифметическое в StrGr_SumData (т.е. данное в i-ой строке 1 столбца StrGr_Data тоже переписывается заново).

Что я делаю не так, и как разрешить данную проблему? Использование глобальной переменной счетчика i и запись с использованием Synchronize приводит к аварийному завершению работы приложения.

И еще вопрос: возможно ли использование 4х потоков, а не двух: т.е. 1 поток - 1 столбец. И как это реализовать? Ведь в конструкторе потока указывается один и тот же объект StringGrid - т.е. как разграничить-то по столбцам?

Заранее спасибо.
RobSys вне форума Ответить с цитированием
Старый 29.03.2011, 23:49   #2
veniside
Старожил
 
Регистрация: 03.01.2011
Сообщений: 2,508
По умолчанию

1) работать с VCL можно только в главном потоке. Без Synchronize() ваша прога будет падать, вопрос просто времени, когда именно.

2) "Синхронизация потоков идет с использованием объекта события E2."
Ничего никуда у вас не идёт. Оба потока фигачат данные в ArNum[] одновременно.

> как разрешить данную проблему?

для начала объясните, что вам нужно. И прочитайте книжку какую-то по мультипоточным приложениям. Сейчас самое простое — весь ваш код переписать заново с нуля.

> возможно ли использование 4х потоков

хоть 50

> т.е. как разграничить-то по столбцам?

передавать номер столбца
"Когда приходит положенное время, человек перестаёт играть в пинбол. Только и всего."
veniside вне форума Ответить с цитированием
Старый 30.03.2011, 18:57   #3
RobSys
Пользователь
 
Регистрация: 12.10.2010
Сообщений: 19
По умолчанию

Тема, в принципе, не актуальна, тк реализовал задачу c использованием средств API.
Спасибо за комментарии.
RobSys вне форума Ответить с цитированием
Старый 30.03.2011, 18:59   #4
Пепел Феникса
Старожил
 
Аватар для Пепел Феникса
 
Регистрация: 28.01.2009
Сообщений: 21,000
По умолчанию

покажите свое решение, а то такое чувство что вы потоки с нуля написали, и просто отсрочили падение.(иль просто скажите что использовали)
Хорошо поставленный вопрос это уже половина ответа. | Каков вопрос, таков ответ.
Программа делает то что написал программист, а не то что он хотел.
Функции/утилиты ждут в параметрах то что им надо, а не то что вы хотите.
Пепел Феникса вне форума Ответить с цитированием
Старый 03.04.2011, 17:55   #5
RobSys
Пользователь
 
Регистрация: 12.10.2010
Сообщений: 19
По умолчанию

Цитата:
Сообщение от Пепел Феникса Посмотреть сообщение
покажите свое решение, а то такое чувство что вы потоки с нуля написали, и просто отсрочили падение.(иль просто скажите что использовали)
Пожалуйста:
Код:
const
  M=3;

var
  hThreadData: array [1..M+2] of THandle;
  ThreadDataID: array [1..M+2] of dword;
  E1: TEvent;
  N: integer;

function WriteData1 (p: pointer): longint; stdcall;
var
  i, j: integer;
begin
  j:=1;
  for i:=1 to N-2 do
      begin
        Sleep(500);
        MainForm.StrGr_Data.Cells[j,i]:=IntToStr(Random(10000));
      end;
end;

function WriteData2 (p: pointer): longint; stdcall;
var
  i, j: integer;
begin
  ------
end;

function WriteData3 (p: pointer): longint; stdcall;
var
  i, j: integer;
begin
  j:=3;
  for i:=1 to N-2 do
      begin
        Sleep(1500);
        MainForm.StrGr_Data.Cells[j,i]:=IntToStr(Random(10000));
        E1.SetEvent;
      end;
end;

function WriteSumData (p: pointer): longint; stdcall;
var
  i, j: integer;
  Sum: integer;
begin
  for i:=1 to N-2 do
      begin
        E1.WaitFor(infinite);
        -----
        Считаем среднее арифметическое строки и вписываем результат в поле
        -----
        E1.ResetEvent;
      end;
end;


procedure TMainForm.FormCreate(Sender: TObject);
var
  i: integer;
begin
  -----
  Инициализируем форму 
  ----
  E1:=TEvent.Create(nil,true,false,'');
end;

procedure TMainForm.But_CalculateClick(Sender: TObject);
begin
  -----
  Создаем потоки
  -----
end;
RobSys вне форума Ответить с цитированием
Старый 03.04.2011, 18:03   #6
Пепел Феникса
Старожил
 
Аватар для Пепел Феникса
 
Регистрация: 28.01.2009
Сообщений: 21,000
По умолчанию

хвалю, все верно
Хорошо поставленный вопрос это уже половина ответа. | Каков вопрос, таков ответ.
Программа делает то что написал программист, а не то что он хотел.
Функции/утилиты ждут в параметрах то что им надо, а не то что вы хотите.
Пепел Феникса вне форума Ответить с цитированием
Старый 03.04.2011, 18:07   #7
RobSys
Пользователь
 
Регистрация: 12.10.2010
Сообщений: 19
По умолчанию

Благодарю
RobSys вне форума Ответить с цитированием
Старый 03.04.2011, 18:19   #8
mss
Заблокирован
 
Регистрация: 27.05.2010
Сообщений: 1,099
По умолчанию

Код:
function WriteData1 (p: pointer): longint; stdcall;
var
  i, j: integer;
begin
  j:=1;
  for i:=1 to N-2 do
      begin
        Sleep(500);
        MainForm.StrGr_Data.Cells[j,i]:=IntToStr(Random(10000)); // обращение в визуальному VCL-контролу в дополнительном потоке !!
      end;
end;
И вот это называется "всё верно" ?)
mss вне форума Ответить с цитированием
Старый 03.04.2011, 18:30   #9
Пепел Феникса
Старожил
 
Аватар для Пепел Феникса
 
Регистрация: 28.01.2009
Сообщений: 21,000
По умолчанию

основной метод это WriteSymData, именно в нем и реализована синхронизация, по названиям я полагаю что остальные используются именно внутри нее.

кстати поправочка, лучше поставьте событие с автосббросом, и убрать все SetEvent оставив лишь после цикла ResetEvent

хотя, мне не нравится что хоть эвентами и защитили грид, но главный поток по прежнему берет данные когда надо.

тут всетаки гораздо лучше синхрониз для обновления использовать(только для обновления)
Хорошо поставленный вопрос это уже половина ответа. | Каков вопрос, таков ответ.
Программа делает то что написал программист, а не то что он хотел.
Функции/утилиты ждут в параметрах то что им надо, а не то что вы хотите.

Последний раз редактировалось Пепел Феникса; 03.04.2011 в 18:59.
Пепел Феникса вне форума Ответить с цитированием
Старый 03.04.2011, 19:08   #10
mss
Заблокирован
 
Регистрация: 27.05.2010
Сообщений: 1,099
По умолчанию

Цитата:
основной метод это WriteSymData
Это вообще не метод, а регулярная функция.

Судя по объявлению
Код:
function WriteData3 (p: pointer): longint; stdcall;
это - некая поточная ф-ция.
В ее теле я в упор не вижу никакой синхронизации.
mss вне форума Ответить с цитированием
Ответ


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



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
stringgrid+колесо мыши=>stringgrid.onclick aalleexxaa Общие вопросы Delphi 5 16.02.2011 16:58
Потоки fredwriter Общие вопросы Delphi 20 13.11.2010 04:16
Потоки Coder86 Общие вопросы Delphi 12 09.06.2010 23:12
потоки пауэрлифтинг Общие вопросы Delphi 5 23.05.2010 14:19
Потоки StudeHt Помощь студентам 1 06.05.2010 16:26