Модераторы: Poseidon, Snowy, bems, MetalFan
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Проблемы с массивом потоков, Проблемы с массивом потоков 
V
    Опции темы
Vitus28
Дата 10.4.2014, 09:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 15
Регистрация: 20.3.2014

Репутация: нет
Всего: нет



Доброго всем времени суток!
Возникла такая проблема. Имеется большой массив данных (примерно 2000 записей, количество каждый день увеличивается). Каждую запись из массива нужно обработать. Для ускорения этого процесса (2000 записей обрабатываются примерно 12часов) решил раскидывать записи между потоками. И тут возникла проблема, переменная объявленная для потока (для хранения ID) затирается при создании следующего потока. Думаю что с исходниками и результатом работы все станет яснее.

На главной форме есть Button и Memo. При нажатии на кнопку запускается "основной поток"
Код

procedure TForm1.Button1Click(Sender: TObject);
begin
  MainThread:=TMainThread.Create(False);
  with MainThread do begin
    FreeOnTerminate:=true;
    Resume;
  end;

end;


модуль основного потока:
Код

type
  TMainThread = class(TThread)
  public
    WorkThread: array [1..3] of boolean;
  protected
    procedure Execute; override;
    procedure Result;
  end;

var
  MainThread: TMainThread;
  text: string;

implementation

procedure TMainThread.Result;
begin
  Form1.Memo1.Lines.Add(text);
end;

procedure TMainThread.Execute;
var
  i, j  : integer; //счетчики
  idWork: integer; //ID свободного потока
begin
  text:='Основной поток запущен';
  Synchronize(Result);
  //не один из дочерних потоков не "в работе"
  for i:=1 to 3 do WorkThread[i]:=false;
  //основной цикл
  for i:=1 to 5 do begin
    //поиск свободного потока
    idWork:=-1;
    repeat
      for j:=1 to 3 do begin
        if not WorkThread[j] then begin
          idWork:=j;
          WorkThread[j]:=true;
          text:='Найден свободный поток ' + IntToStr(j);
          Synchronize(Result);
          break;
        end;
      end;
      if idWork = -1 then begin
        text:='Свободный поток не найден. Ожидание...';
        Synchronize(Result);
        sleep(1000);
      end;
    until idWork <> -1;

    ChildThread[idWork]:=TChildThread.Create(true);
    with ChildThread[idWork] do begin
      FreeOnTerminate:=true;
      Number:=idWork;
      Resume;
    end;
  end;
  text:='Основной поток завершен';
  Synchronize(Result);
end;


модуль дочернего потока:
Код

type
  TChildThread = class(TThread)
  private
    { Private declarations }
  public
    Number: integer;
    destructor Destroy; override;
    procedure Execute; override;
    procedure Result;
  end;

var
  ChildThread: array [1..3] of TChildThread;
  text1: string;

implementation

procedure TChildThread.Result;
begin
  Form1.Memo1.Lines.Add(text1);
end;

destructor TChildThread.Destroy;
begin
  with MainThread do begin
    WorkThread[Number]:=false;
  end;
end;

procedure TChildThread.Execute;
begin
  text1:='Дочерний поток ' + IntToStr(Number) + ' запущен';
  Synchronize(Result);
  sleep(2000);
  text1:='Дочерний поток ' + IntToStr(Number) + ' остановлен';
  Synchronize(Result);
end;


Суть такова. В "главном потоке" находится массив который нужно обработать (for i:=1 to 5 do) и имеется массив дочернего патока (ну допустим на 3 единицы). Т.е. бегая по основному циклу я ищу какой из этих трех дочерних потоков отработал и запускаю его на очередную запись. Чтобы поток знал что он вообще обрабатывает при объявлении у него указана переменная Number.
Вот результат:
Цитата

Основной поток запущен
Найден свободный поток 1
Найден свободный поток 2
Дочерний поток 1 запущен
Дочерний поток 2 запущен
Найден свободный поток 3
Свободный поток не найден. Ожидание...
Дочерний поток 3 запущен
Свободный поток не найден. Ожидание...
Дочерний поток 2 остановлен
Дочерний поток 2 остановлен
Найден свободный поток 1
Дочерний поток 3 остановлен
Найден свободный поток 2
Дочерний поток 1 запущен
Основной поток завершен
Дочерний поток 2 запущен
Дочерний поток 1 остановлен
Дочерний поток 2 остановлен


Дочерний 1 запустился, затем 2, затем 3. А потом Дочерний поток 2 остановлен и снова Дочерний поток 2 остановлен.
Как быть, жду Ваших вариантов и предложений!

Исходники по ссылке

Это сообщение отредактировал(а) Vitus28 - 10.4.2014, 09:57

Присоединённый файл ( Кол-во скачиваний: 0 )
Присоединённый файл  code.rar 8,02 Kb
PM MAIL   Вверх
Poseidon
Дата 10.4.2014, 10:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Delphi developer
****


Профиль
Группа: Комодератор
Сообщений: 5273
Регистрация: 4.2.2005
Где: Гомель, Беларусь

Репутация: 53
Всего: 133



Я лишь укажу на очевидные ошибки. Если не поможет, то нужно уже смотреть детально.
  • Если мы вызываем TMainThread.Create(False), то Resume там уже излишнее.
  • Переменные text и text1 нужно сделать полями классов TMainThread и TChildThread.
Второй пункт, мне кажется, и есть причина проблемы. 

Если бегло посмотреть, то получается следующее: в TChildThread.Execute в потоке 1 выполняется строка text1:='Дочерний поток ' + IntToStr(Number) + ' остановлен'; В text1 у нас "Дочерний поток 1 остановлен". Затем тут же в потоке 2 выполняется эта же строка. В text1 у нас уже "Дочерний поток 2 остановлен". Затем в первом потоке выполняется Synchronize(Result) и в memo записывается то, что в text1, а там у нас уже "Дочерний поток 2 остановлен". Потом во втором потоке выполняется Synchronize(Result) и в memo снова записывается "Дочерний поток 2 остановлен".

Вообще при работе с несколькими потоками нужно быть внимательнее при использовании глобальных переменных (а правильно вообще не использовать ничего глобального).


--------------------
Если хочешь, что бы что-то работало - используй написанное, 
если хочешь что-то понять - пиши сам...
PM MAIL ICQ   Вверх
PointerToNil
Дата 10.4.2014, 14:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата



*


Профиль
Группа: Участник
Сообщений: 108
Регистрация: 17.6.2013

Репутация: 3
Всего: 6



1. вроде бы, "главный" поток процессор не занимает (лишь распределяет задачи), но занимается выводом на форму через synchronize (ужас!)
=> он абсолютно НЕ НУЖЕН, с этим отлично справится основной (VCL) поток
2. вы пишете "В "главном потоке" находится массив который нужно обработать"
данные не НАХОДЯТСЯ в потоках! потоки лишь исполняют инструкции! для потоков все данные как бы глобальные (ну, кроме threadvar), только программист может себя ограничить тем, что просто не обращается в потоке к "чужим" данным (ограничивается полями объекта текущего потока). ОБЪЕКТ потока - это тоже данные и они только номинально связаны с конкретным ПОТОКОМ ИСПОЛНЕНИЯ инструкций из T{My}Thread.Execute
3. я бы ввел глобальную переменную (лучше - поле формы и т.п.) "номер последней уже взятой на обработку записи", каждый освободившийся дочерний поток увеличивал бы её через interlockedincrement и начинал этой записью заниматься, пока все не исчерпаются (без всяких остановок)
никаких synchronize и никаких sleep в дочерних
основной поток может следить за ходом работ через ту же глобальную переменную (в нем может быть и sleep) 
PM MAIL   Вверх
Vitus28
Дата 11.4.2014, 05:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 15
Регистрация: 20.3.2014

Репутация: нет
Всего: нет



Poseidon, 
Цитата

Если мы вызываем TMainThread.Create(False), то Resume там уже излишнее

с этим согласен (попутал) - но по факту особо ни на что не влияет
Цитата

Второй пункт, мне кажется, и есть причина проблемы. 

попробовал предоженный варинат - без изменений

Хотел сказать что приведенный пример - это облегченный и упрощенный вариант задачи, которую я решаю. Что бы не нагружать его кодом был сделан произвольный цикл, sleep используются только для того чтобы сделать задержку выполнения.

И сразу поясню. Я понимаю что когда запускается программа на исполнения создается основной (главный) поток программы. В своём описании под "главным потоком" я понимаю первый поток (модуль основного потока), в котором у меня находится цикл по данным. В этом потоке я создаю мной названные "дочерние потоки", которые призваны уменьшить время требуемое для обработки инфы.

PointerToNil, 
Цитата

вы пишете "В "главном потоке" находится массив который нужно обработать"

В моем "главном потоке" (не путать с главным или основным потоком самого приложения. "Главным" назвал его я, можно назвать master или как душе угодно) из файла xls читываются, проверяются данные ip, url, domain. ip нужно раза 2-4 пингануть, url проверить на доступность, и ели он доступен по трассирнуть. Этим как раз я и хочу озадачить дочерние потоки (их количество будет регулироваться настройкой), в приведенном примере их 3.
Ну вот как-то так. Решение пока не надено, пробую различные варианты, жду Ваших предложений

PM MAIL   Вверх
Vitus28
Дата 11.4.2014, 09:04 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 15
Регистрация: 20.3.2014

Репутация: нет
Всего: нет



Poseidon, 
Цитата

Второй пункт, мне кажется, и есть причина проблемы. 

Когда пробовал первый раз видимо что-то намутил. Сейчас закинул переменные text и text1 в переменные потока и все стало замечтательно smile
Всем болшое спасибо за помощь!

Это сообщение отредактировал(а) Vitus28 - 11.4.2014, 09:05
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Delphi: Общие вопросы"
SnowyMetalFan
bemsPoseidon
Rrader

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Литературу по Дельфи обсуждаем здесь
  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь
  • 90% ответов на свои вопросы можно найти в DRKB (Delphi Russian Knowledge Base) - крупнейшем в рунете сборнике материалов по Дельфи


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Snowy, MetalFan, bems, Poseidon, Rrader.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Delphi: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0458 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.