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

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

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

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

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

Ответ
 
Опции темы Поиск в этой теме
Старый 21.03.2011, 11:59   #1
NieL
Форумчанин
 
Регистрация: 17.11.2008
Сообщений: 116
По умолчанию Многопоточность при работе со списком

Имеется массив целочисленных идентификаторов:

.., 1, 2, 7, 9, 10, 21, 23, ...

Задача: перебрать массив в несколько потоков (Поток будет брать из массива значение, подставлять его в get-запрос и отправлять на web-сервер (пишу утилиту для проверки существования картинок на web-сервере)). Собственно вопрос, как скармливать потоку значения массива, чтобы избежать одновременного доступа к ожному и тому же значению массива из других потоков. Все что находил - не фонтан, хотелось бы увидеть грамотный подход к этому вопросу. Наткнулся на похожий вопрос на одном из форумов, там советовали использовать пул потоков. Начал копать в сторону TIdSchedulerOfThreadPool. Описания его работы, примеров использования - ничего не нашел.
NieL вне форума Ответить с цитированием
Старый 21.03.2011, 12:09   #2
mss
Заблокирован
 
Регистрация: 27.05.2010
Сообщений: 1,099
По умолчанию

Цитата:
избежать одновременного доступа к ожному и тому же значению массива из других потоков
Если предполагается мультипоточный доступ к ресурсу только для его чтения, то никаких специальных телодвижений по "избежанию" не требуется.
mss вне форума Ответить с цитированием
Старый 21.03.2011, 12:13   #3
NieL
Форумчанин
 
Регистрация: 17.11.2008
Сообщений: 116
По умолчанию

для примера, 2 потока работают с массивом A, одновременно и первый и второй взяли элемент N массива A, что делать?.
NieL вне форума Ответить с цитированием
Старый 21.03.2011, 12:22   #4
mss
Заблокирован
 
Регистрация: 27.05.2010
Сообщений: 1,099
По умолчанию

Цитата:
одновременно и первый и второй взяли элемент N массива A, что делать?.
Пересмотреть в корне логику мультипоточной организации вычислений.
Потоки ничего не должны ни откуда "брать" сами, их задача - выполнять расчеты с переданными им потоком-диспетчером параметрами, а не лезть наперегонки кто во что горазд в глобальный массив.

Иллюстрация логики потока-диспетчера:

Код:
for i := 0 to N-1 do
  TMyThread.Create(MyIntArr[i]);
Для сравнительно небольшого по размеру массива это самое простое и вполне приемлемое решение.
mss вне форума Ответить с цитированием
Старый 21.03.2011, 12:24   #5
Johnson
кривокодер ;)
Форумчанин
 
Аватар для Johnson
 
Регистрация: 20.06.2008
Сообщений: 707
По умолчанию

Посмотреть в сторону процедуры синхронизации потоков и в сторону критических секций.
"А как написать праграму?, "ришыти задачьку очинь нада" ©с форума. Жить становится интереснее, жить становится веселее...
{Быть или не быть} {Неуспешный суицид}
Johnson вне форума Ответить с цитированием
Старый 21.03.2011, 12:55   #6
NieL
Форумчанин
 
Регистрация: 17.11.2008
Сообщений: 116
По умолчанию

Цитата:
Сообщение от mss Посмотреть сообщение
Пересмотреть в корне логику мультипоточной организации вычислений.
Потоки ничего не должны ни откуда "брать" сами, их задача - выполнять расчеты с переданными им потоком-диспетчером параметрами, а не лезть наперегонки кто во что горазд в глобальный массив.

Иллюстрация логики потока-диспетчера:

Код:
for i := 0 to N-1 do
  TMyThread.Create(MyIntArr[i]);
Для сравнительно небольшого по размеру массива это самое простое и вполне приемлемое решение.
сложно сказать какой массив будет (на сайте в среднем от 1500 до 7000 картинок, возможно и больше).

Вот к примеру:

Код:
unit Unit2;

interface

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

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

  TMyThread = class(TThread)
  protected
    procedure Execute; override;
  end;

var
  Form2: TForm2;

  IDs: array [1..14] of Integer =
    (1, 3, 4, 7, 8, 9, 17, 24, 26, 27, 29, 31, 42, 58);

  thread_for_run: Integer = 5;

implementation

{$R *.dfm}

{ TMyThread }

procedure TMyThread.Execute;
begin
  // как правильно брать из списка очередное значения?,
    // как правильно сделать проверку, пока не пройден весь массив
    // (на уровне всех потоков)
    // поток будет брать из списка очередное значение и подставлять в Get-запрос

  //...

  //IdHttp.Get(Format(..., [.., <значение из массива IDs> ,..]))

end;

procedure TForm2.Button1Click(Sender: TObject);
var
  I: Integer;
begin
  for I := 1 to thread_for_run do // для примера 5 потоков
  begin
    TMyThread.Create(False);

  end;

end;

end.
Если изначально я создаю 5 потоков, а в массиве 3000 элементов как мне каждый элемент передать потоку как параметр?
NieL вне форума Ответить с цитированием
Старый 21.03.2011, 13:29   #7
Johnson
кривокодер ;)
Форумчанин
 
Аватар для Johnson
 
Регистрация: 20.06.2008
Сообщений: 707
По умолчанию

В данном случае передавать потоку ничего не нужно. Пусть он сам берет из глобальной переменной данные. Чтоб не вышел случай запрета доступа - используйте критические секции во время чтения из переменной.
Код:
_CS:=TCriticalSection.Create;
/////
_CS.Enter;
{код }
_CS.Leave;
Внутри этой конструкции код будет исполняться только в одном потоке, остальные потоки (включая основной) будут приостановлены.
НО, есть одно "НО"... Для доступа к этому массиву даже из основного потока желательно так же использовать крит секции.
"А как написать праграму?, "ришыти задачьку очинь нада" ©с форума. Жить становится интереснее, жить становится веселее...
{Быть или не быть} {Неуспешный суицид}
Johnson вне форума Ответить с цитированием
Старый 21.03.2011, 13:37   #8
veniside
Старожил
 
Регистрация: 03.01.2011
Сообщений: 2,508
По умолчанию

Цитата:
// как правильно брать из списка очередное значения?,
// как правильно сделать проверку, пока не пройден весь массив
// (на уровне всех потоков)
Все это можно сделать с помощью InterlockedIncrement(). Типа такого:

PHP код:
  // внутри вашего потока
while (okToRunThread) do begin
  
//
  
nextIndex := InterlockedIncrement(g_index);
  if (
nextIndex < List.Countthen
    
// делайте то, что вам нужно с List[nextIndex]
  
else
    
// завершить работу потока
end

g_index - глобальная переменная, которой присваивается индекс первого элемента списка - 1 перед запуском потоков.
"Когда приходит положенное время, человек перестаёт играть в пинбол. Только и всего."

Последний раз редактировалось veniside; 21.03.2011 в 13:40.
veniside вне форума Ответить с цитированием
Старый 21.03.2011, 13:55   #9
NieL
Форумчанин
 
Регистрация: 17.11.2008
Сообщений: 116
По умолчанию

Цитата:
Сообщение от veniside Посмотреть сообщение
Все это можно сделать с помощью InterlockedIncrement(). Типа такого:

PHP код:
  // внутри вашего потока
while (okToRunThread) do begin
  
//
  
nextIndex := InterlockedIncrement(g_index);
  if (
nextIndex < List.Countthen
    
// делайте то, что вам нужно с List[nextIndex]
  
else
    
// завершить работу потока
end

g_index - глобальная переменная, которой присваивается индекс первого элемента списка - 1 перед запуском потоков.
Круто, про InterlockedIncrement не знал. Встречный вопрос, с точки зрения организации кода, обращение из потока к данным извне (в данном случае к глобальной переменной) будет корректно, не будет противоречить логике многопоточности? Может разделить массив на количество потоков и каждому в конструктор скормить свой массив? Таким образом никакого обращения к данным из вне, все изолированно. Нужно ваше мнение.
NieL вне форума Ответить с цитированием
Старый 21.03.2011, 13:56   #10
Johnson
кривокодер ;)
Форумчанин
 
Аватар для Johnson
 
Регистрация: 20.06.2008
Сообщений: 707
По умолчанию

NieL, я для чего объяснял про критические секции?...
"А как написать праграму?, "ришыти задачьку очинь нада" ©с форума. Жить становится интереснее, жить становится веселее...
{Быть или не быть} {Неуспешный суицид}
Johnson вне форума Ответить с цитированием
Ответ


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



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Ошибка при работе с потоком Claster Помощь студентам 1 14.10.2009 16:06
Многопоточность при отправке почты sanchopansa Работа с сетью в Delphi 4 04.10.2008 14:57
Проблема при работе с БД HAMMAN БД в Delphi 3 29.03.2008 14:42
Ошибка при работе с БД malevich БД в Delphi 8 25.11.2007 15:10