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

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

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

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

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

Ответ
 
Опции темы Поиск в этой теме
Старый 11.08.2011, 23:54   #1
jskorvin
Пользователь
 
Регистрация: 27.09.2010
Сообщений: 16
Вопрос Запуск потоков в цикле, как?

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

Код конечно условный, но суть полностью отражает.
Нужно запускать не больше 11 потоков одновременно, while в цикле какраз для ожидания уменьшения количества работающих потоков.

форма
Код:
unit main;

interface

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

type
  TForm1 = class(TForm)
    Button1: TButton;
    Memo1: TMemo;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  Cth: integer; // счетчик количества запущеных потоков

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var
TH: gen;
i, j, k: integer;
begin

 for i := 0 to 10 do
   for j := 0 to 5 do
     for k := 0 to 3 do
     begin

        while Cth > 10 do
        Application.ProcessMessages;


        TH:=gen.Create(true);
        TH.FreeOnTerminate:=true;
        TH.value:=i+j+k;
        TH.Resume;

//      memo1.Lines.Add(IntToStr(i+j+k));
     end;




end;

end.
На форме кнопка и мемо

Поток
Код:
unit Tgen;

interface

uses
  Classes, sysutils;

type
  gen = class(TThread)
  private
    { Private declarations }
  public
  value: integer;
  protected
    procedure Execute; override;
    procedure incCth;  // увеличение количества работающих потоков
    procedure decCth;  // уменьшение количества работающих потоков
    procedure toMemo;  // вывод чегото в мемо
  end;

implementation
      uses main;

{ gen }

procedure gen.incCth;
begin
inc(main.Cth)
end;


procedure gen.decCth;
begin
dec(main.Cth)
end;


procedure gen.toMemo;
begin
 main.Form1.Memo1.Lines.Add(IntToStr(value));
end;

procedure gen.Execute;
begin
 Synchronize(incCth);

   Synchronize(toMemo);

 Synchronize(decCth);
 self.Terminate;
end;


end.

Мне так кажется происходит следующее: отрабатывают циклы, создаются потоки, после этого все потоки разом пытаются стартануть. В голову приходит синхронизация, но как? Цикл то поидее и так в главном (VCL) потоке отрабатывает. Если устроить вывод в мемо прямо из цикла то все работает как положено.

Чего-то я видимо в свое время не дочитал, помогите пожалуйста разобраться.

Проект прикрепляю, писалось в Delphi XE. Осторожно подвешивает машину.
Вложения
Тип файла: rar help.rar (98.6 Кб, 14 просмотров)
jskorvin вне форума Ответить с цитированием
Старый 12.08.2011, 00:19   #2
veniside
Старожил
 
Регистрация: 03.01.2011
Сообщений: 2,508
По умолчанию

1) замените Synchronize(incCth); и Synchronize(decCth); на InterlockedIncrement(incCth); и InterlockedDecrement(incCth); соответсвенно. Каждый лишний вызов Synchronize() — это выстрел в голову главному потоку.

2) походу, как только потоков становится > 10, ваш while дедлочит дальнейшие вызовы Synchronize(), но точно не уверен.

3) Избавьтесь вобще от Synchronize(), общайтесь с мемо через PostMessage() или с использованием одного из десятка других методов межпоточного взаимодействия.
"Когда приходит положенное время, человек перестаёт играть в пинбол. Только и всего."
veniside вне форума Ответить с цитированием
Старый 12.08.2011, 08:12   #3
jskorvin
Пользователь
 
Регистрация: 27.09.2010
Сообщений: 16
По умолчанию

Цитата:
Сообщение от veniside Посмотреть сообщение
1) замените Synchronize(incCth); и Synchronize(decCth); на InterlockedIncrement(incCth); и InterlockedDecrement(incCth); соответсвенно. Каждый лишний вызов Synchronize() — это выстрел в голову главному потоку.

2) походу, как только потоков становится > 10, ваш while дедлочит дальнейшие вызовы Synchronize(), но точно не уверен.

3) Избавьтесь вобще от Synchronize(), общайтесь с мемо через PostMessage() или с использованием одного из десятка других методов межпоточного взаимодействия.
InterlockedIncrement действительно оптимальнее использовать для увеличения и уменьшения счетчика, спасибо. Но даже если убрать все функции из потока проблема остается =(
jskorvin вне форума Ответить с цитированием
Старый 12.08.2011, 13:20   #4
veniside
Старожил
 
Регистрация: 03.01.2011
Сообщений: 2,508
По умолчанию

Так, проблема хуже, чем я думал. Потоки действительно накапливаются и большинство из них запускается фактически уже после того, как программа вышла из Button1Click(), так что проверка (Cth > 10) никогда не срабатывает.

Что можно сделать? Добавить Sleep(10); после TH.Resume;
Это даст шанс хоть кому-то запуститься и не насиловать систему созданием и одновременным запуском 264 потоков.

Походу обнаружилось, что все потоки, основанные на TThread создаются в suspensed mode, не зависимо от параметра CreateSuspensed. Более того, если у потока FreeOnTerminate = True, то его в конце прогонят через общую критическую секцию, из-за чего потоки скапливаются на выходе. Ну а самый ужос творится внутри Synchronize(), но это и так было известно )
"Когда приходит положенное время, человек перестаёт играть в пинбол. Только и всего."
veniside вне форума Ответить с цитированием
Ответ


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



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Определение делегатов потоков в цикле Lazio C# (си шарп) 1 18.07.2011 00:43
Запуск нескольких потоков bulldog5293 Общие вопросы Delphi 3 11.11.2010 18:24
Параллельный запуск двух потоков Sam Gold Общие вопросы C/C++ 0 30.04.2010 20:56
Как реализовать запуск и контроль нескольких однотипных потоков. Son Общие вопросы Delphi 5 29.04.2010 08:40
Запуск потоков в цикле VALERO Общие вопросы Delphi 11 01.03.2009 14:57