![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Потоки [D7, WinXP]
YURY © (2011-11-29 11:42:00)Добрый день.
Требуется выполнить n потоков одного класса, каждый из которых будет выполнять свои действия в зависимости от заданных параметров. Поток Б должен стартовать после завершения потока А.
Реализую на простейшем примере из двух потоков (форма с двумя компонентами TEdit и кнопкой и модуль класса потока). При нажатии на кнопку первый поток должен выводить в первый TEdit значения от 0 до 20000, затем второй поток должен выводить во второй TEdit значения от 50000 до 70000. По факту же после завершения работы первого потока возникает ошибка "Thread error: Неверный дескриптор (6)" и второй поток не отрабатывает. Почему возникает ошибка и как её устранить?
Код для примера (форма и модуль):
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
Edit1: TEdit;
Edit2: TEdit;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
uses Unit2;
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
var
ThreadArray: Array of TMyThread;
begin
SetLength(ThreadArray, 2);
ThreadArray[0] := TMyThread.Create(True);
ThreadArray[0].FreeOnTerminate := True;
ThreadArray[0].Priority := tpNormal;
ThreadArray[0].j := 0;
ThreadArray[0].k := 20000;
ThreadArray[0].ptrEdit := @Edit1;
ThreadArray[1] := TMyThread.Create(True);
ThreadArray[1].FreeOnTerminate := True;
ThreadArray[1].Priority := tpNormal;
ThreadArray[1].j := 50000;
ThreadArray[1].k := 70000;
ThreadArray[1].ptrEdit := @Edit2;
ThreadArray[1].ptrThread := @ThreadArray[0];
ThreadArray[0].Resume;
ThreadArray[1].Resume;
end;
end.
unit Unit2;
interface
uses
Classes, StdCtrls, SysUtils;
type
TMyThread = class(TThread)
public
j, k: Integer;
ptrEdit: ^TEdit;
ptrThread: ^TMyThread;
protected
procedure Execute; override;
end;
implementation
procedure TMyThread.Execute;
var
i: Integer;
begin
if Assigned(ptrThread) then ptrThread^.WaitFor;
for i := j to k do
ptrEdit^.Text := IntToStr(i);
end;
end.
P.S. Если в модуле потока убрать инструкцию "if Assigned(ptrThread) then ptrThread^.WaitFor;", то оба потока отрабатывают синхронно, но вся суть в том, чтобы они работали последовательно.
sniknik (2011-11-29 12:55:00) [21]> для сокращения общего времени процесса.
общее время процесса от добавления потоков всегда увеличивается...
http://russian.joelonsoftware.com/Articles/HumanTaskSwitchesConsider.html
параллельность нужна не для этого.
Медвежонок Пятачок (2011-11-29 12:55:00) [22]запускай на сервере.
нужна асинхронность - запускай через job'ы
YURY (2011-11-29 12:53:00) [23]Сергей М., Очерёдность у них определена во входных параметрах. Поэтому одни выполняются сразу, а иные попросту ждут завершения других. Никто ни за кем не шпионит. Так все же, как реализовать эту идею в одном классе? Если вернуться к примеру с VCL, то что не так и почему ошибка? Ведь второй поток таки ожидает завершения первого и только потом возникает исключение... Почему оно возникает и как его избежать?
Anatoly Podgoretsky (2011-11-29 12:52:00) [24]Зачем же врешь?
ThreadArray[0] := TMyThread.Create(True);
ThreadArray[1] := TMyThread.Create(True);
YURY (2011-11-29 12:48:00) [25]Я не упомянул, что сервер у нас оракловый и пользователей несколько сотен, так что в этом отношении всё нормально.
Сергей М. (2011-11-29 12:47:00) [26]
> как с помощью этого одного класса реализовать возможность
> параллельного, а также последовательного запуска ХП, в зависимости
> от переданных параметров?
Да не должны вообще об этом заботиться потоки, исполняющие твои ХП !
Их дело - запускать на выполнение указанные им запросы.
А диспетчеризацией должен быть озабочен отдельныйпоток, если угодно - доп.поток другогокласса или хоть тот же осн.поток.
А у тебя сейчас доп.потоки занимаются совсем несвойственной им работой - шпионят друг за другом в попытке определить свою очередность в этой каше)
YURY (2011-11-29 12:46:00) [27]Сергей М., может с точки зрения вашей теории это и глупости, но практика показывает значительное сокращение общего времени выполнения при параллельном запуске нескольких хранимых процедур. Реально: Последовательное выполнение 12-ти боевых процедур занимает 4,5 часа. Их параллельное выполнение - чуть более полутора часов. Разница очевидна. Проверено многократно на различных наборах хранимок.
Anatoly Podgoretsky (2011-11-29 12:43:00) [28]> Сергей М. (29.11.2011 12:35:25) [25]
У меня 14 потоков забивают все ядра сервера по максимуму
Anatoly Podgoretsky (2011-11-29 12:42:00) [29]> Сергей М. (29.11.2011 12:35:25) [25]
И поставит сервер на колени
Медвежонок Пятачок (2011-11-29 12:42:00) [30]создать еще одну хранимую процедуру.
передавать в нее управляющую информацию что и в какой последовательности запускать.
выполнить ее.
Anatoly Podgoretsky (2011-11-29 12:41:00) [31]> YURY (29.11.2011 12:26:23) [23]
Ничего не значищие слова
YURY (2011-11-29 12:40:00) [32]Парни, попробую ещё раз, сжато.
Требуется выполнить набор хранимых процедур. Для ускорения общего времени выполнения какие-то из них нужно запускать одновременно, а какие-то - строго после окончания других (цепочка последовательности динамическая - по выбору пользователя - и находится в БД). Причём и набор хранимок также формируется пользователем динамически. Т.е. я не знаю заранее какие именно хранимки и в какой последовательности придётся выполнять. Это всё будет считано из БД в процессе выполнения. Потому и создан один класс потока, запускающего переданную ему в параметрах хранимую процедуру. Но вопрос остался - как с помощью этого одного класса реализовать возможность параллельного, а также последовательного запуска ХП, в зависимости от переданных параметров?
Сергей М. (2011-11-29 12:35:00) [33]
> YURY (29.11.11 12:28) [24]
> на практике параллельное выполнение различных хранимых процедур
> (каждую в своем потоке) значительно быстрее их последовательного
> выполнения. Проверено.
> <Цитата>
Глупости.
Даже если сервер умудрится идеально (что никогда не случится) распределить исполнение N твоих (и не только твоих - ты же не единственный клиент у сервера) параллельных запросов по своим N потокам, каждый из которых исполняется отдельным "свободным" ядром, то дальнейшее потенциальное увелечение N сведет всю "быстроту" на нет.
YURY (2011-11-29 12:28:00) [34]Сергей М., на практике параллельное выполнение различных хранимых процедур (каждую в своем потоке) значительно быстрее их последовательного выполнения. Проверено.
YURY (2011-11-29 12:26:00) [35]Anatoly Podgoretsky, для выполнения определённых действий в основном потоке (в боевой схеме).
Медвежонок Пятачок (2011-11-29 12:25:00) [36]А нашиша их параллельно-то на выполнение запускать ?
это потому что его очень умные потоки научены выполнять только одну хранимку.
запустить их несколько по списку - это задача на следующую пятилетку.
Сергей М. (2011-11-29 12:23:00) [37]
> YURY (29.11.11 12:19) [18]
Ну с последовательным синхронным выполнением ХП еще понятно.
А нашиша их параллельно-то на выполнение запускать ?
Серверу твои параллельно работающие потоки до лампочки - у него своя кухня из своих ядер, потоков и приоритетов.
Anatoly Podgoretsky (2011-11-29 12:22:00) [38]Создай два класса и запускай нужный. Не вижу нужды в одном
Anatoly Podgoretsky (2011-11-29 12:21:00) [39]И зачем ThreadArray?
YURY (2011-11-29 12:19:00) [40]Anatoly Podgoretsky, я не знаю заранее сколько хранимок и какие именно будут выполняться. Эта информация считывается из БД в процессе выполнения. Потому и реализован один класс потока, выполняющий задаваемую в параметрах хранимую процедуру.