Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Начинающим";
Текущий архив: 2012.03.11;
Скачать: [xml.tar.bz2];

Вниз

Потоки   Найти похожие ветки 

 
YURY   (2011-11-29 11:42) [0]

Добрый день.
Требуется выполнить 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;", то оба потока отрабатывают синхронно, но вся суть в том, чтобы они работали последовательно.


 
Медвежонок Пятачок ©   (2011-11-29 11:51) [1]

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


 
Медвежонок Пятачок ©   (2011-11-29 11:52) [2]

Заодно сожги вот эту ересь.

ThreadArray[0].ptrEdit := @Edit1;
ptrEdit^.Text := IntToStr(i);


 
sniknik ©   (2011-11-29 11:55) [3]

> Поток Б должен стартовать после завершения потока А.
убивает всю идею с
> Требуется выполнить n потоков одного класса

достаточно 1 потока последовательно выполняющего n действий...

> Почему возникает ошибка и как её устранить?
а не обращайся к объектам VCL формы без синхронизации. или думаешь обманул систему своими указателями...?


 
Anatoly Podgoretsky ©   (2011-11-29 11:57) [4]

OnTerminate в первом или обеих потоках


 
Сергей М. ©   (2011-11-29 12:01) [5]

>   ptrEdit^.Text := IntToStr(i); // за это можно и на костер


 
Сергей М. ©   (2011-11-29 12:04) [6]


> Поток Б должен стартовать после завершения потока А


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


 
YURY   (2011-11-29 12:08) [7]

Благодарю откликнувшихся, но видимо требуется уточнение. Пример реализован лишь для тестирования идеи. Идея в том, что все потоки должны быть одного класса. В зависимости от заданных параметров часть потоков должны стартовать синхронно, а определённые одни - строго поле определённых других других. VCL здесь не причём - сделал для простоты, тем более что и с VCL потоки синхронно работают, если убрать WaitFor. На деле же каждый поток должен выполнять свою хранимую процедуру, но определённые процедуры должны быть выполнены строго после окончания других. Цепочка последовательности выполнения процедур считывается из БД.


 
Медвежонок Пятачок ©   (2011-11-29 12:10) [8]

Ну и при чем здесь тогда твой "Неверный дескриптор"?
если ты и так все знаешь и сам создал ошибку для простоты


 
Медвежонок Пятачок ©   (2011-11-29 12:14) [9]

Пример реализован лишь для тестирования идеи.
поток должен выполнять свою хранимую процедуру
Цепочка последовательности выполнения процедур считывается из БД.

идея дебильная.
потоки не нужны.
так как последовательность выполнения детерминирована и лежит в бд, нужна одна хранимая процедура-диспетчер, которая выполнит все остальные хранимки.


 
YURY   (2011-11-29 12:14) [10]

Медвежонок Пятачок, ошибка эта возникает в боевой схеме (с хранимыми процедурами). Для простоты я лишь реализовал идею в VCL. Суть от этого не меняется.


 
Сергей М. ©   (2011-11-29 12:14) [11]

В идеале должен быть поток-диспетчер, отвечающий за запуск доп.потоков (которые не должны знать ничего о существовании друг друга) в нужной последовательности.

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


 
Медвежонок Пятачок ©   (2011-11-29 12:15) [12]

Медвежонок Пятачок, ошибка эта возникает в боевой схеме

Про эту ошибку тебе уже несколько человек все рассказали.


 
Anatoly Podgoretsky ©   (2011-11-29 12:15) [13]

> Сергей М.  (29.11.2011 12:04:06)  [6]

Это потуму что они не умеют устранить зависание интерфейса другими методами.


 
Anatoly Podgoretsky ©   (2011-11-29 12:16) [14]

> YURY  (29.11.2011 12:08:07)  [7]

Не разумно тогда делать потоки одного класса, ну разве что бы запутать.


 
YURY   (2011-11-29 12:16) [15]

Медвежонок Пятачок, некоторые хранимки должны выполняться синхронно для сокращения общего времени процесса.


 
Медвежонок Пятачок ©   (2011-11-29 12:18) [16]

Медвежонок Пятачок, некоторые хранимки должны выполняться синхронно для сокращения общего времени процесса.

и чего?
создание потока в твоей программе увеличивает число ядер процессора sql сервера?


 
Anatoly Podgoretsky ©   (2011-11-29 12:19) [17]

Твой пример только запутывает.


 
YURY   (2011-11-29 12:19) [18]

Anatoly Podgoretsky, я не знаю заранее сколько хранимок и какие именно будут выполняться. Эта информация считывается из БД в процессе выполнения. Потому и реализован один класс потока, выполняющий задаваемую в параметрах хранимую процедуру.


 
Anatoly Podgoretsky ©   (2011-11-29 12:21) [19]

И зачем ThreadArray?


 
Anatoly Podgoretsky ©   (2011-11-29 12:22) [20]

Создай два класса и запускай нужный. Не вижу нужды в одном


 
Сергей М. ©   (2011-11-29 12:23) [21]


> YURY   (29.11.11 12:19) [18]


Ну с последовательным синхронным выполнением ХП еще понятно.
А нашиша их параллельно-то на выполнение запускать ?
Серверу твои параллельно работающие потоки до лампочки - у него своя кухня из своих ядер, потоков и приоритетов.


 
Медвежонок Пятачок ©   (2011-11-29 12:25) [22]

А нашиша их параллельно-то на выполнение запускать ?

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


 
YURY   (2011-11-29 12:26) [23]

Anatoly Podgoretsky, для выполнения определённых действий в основном потоке (в боевой схеме).


 
YURY   (2011-11-29 12:28) [24]

Сергей М., на практике параллельное выполнение различных хранимых процедур (каждую в своем потоке) значительно быстрее их последовательного выполнения. Проверено.


 
Сергей М. ©   (2011-11-29 12:35) [25]


> YURY   (29.11.11 12:28) [24]


> на практике параллельное выполнение различных хранимых процедур
> (каждую в своем потоке) значительно быстрее их последовательного
> выполнения. Проверено.
> <Цитата>


Глупости.
Даже если сервер умудрится идеально (что никогда не случится) распределить исполнение N твоих (и не только твоих - ты же не единственный клиент у сервера) параллельных запросов по своим N потокам, каждый из которых исполняется отдельным "свободным" ядром, то дальнейшее потенциальное увелечение N сведет всю "быстроту" на нет.


 
YURY   (2011-11-29 12:40) [26]

Парни, попробую ещё раз, сжато.
Требуется выполнить набор хранимых процедур. Для ускорения общего времени выполнения какие-то из них нужно запускать одновременно, а какие-то - строго после окончания других (цепочка последовательности динамическая - по выбору пользователя - и находится в БД). Причём и набор хранимок также формируется пользователем динамически. Т.е. я не знаю заранее какие именно хранимки и в какой последовательности придётся выполнять. Это всё будет считано из БД в процессе выполнения. Потому и создан один класс потока, запускающего переданную ему в параметрах хранимую процедуру. Но вопрос остался - как с помощью этого одного класса реализовать возможность параллельного, а также последовательного запуска ХП, в зависимости от переданных параметров?


 
Anatoly Podgoretsky ©   (2011-11-29 12:41) [27]

> YURY  (29.11.2011 12:26:23)  [23]

Ничего не значищие слова


 
Медвежонок Пятачок ©   (2011-11-29 12:42) [28]

создать еще одну хранимую процедуру.
передавать в нее управляющую информацию что и в какой последовательности запускать.
выполнить ее.


 
Anatoly Podgoretsky ©   (2011-11-29 12:42) [29]

> Сергей М.  (29.11.2011 12:35:25)  [25]

И поставит сервер на колени


 
Anatoly Podgoretsky ©   (2011-11-29 12:43) [30]

> Сергей М.  (29.11.2011 12:35:25)  [25]

У меня 14 потоков забивают все ядра сервера по максимуму


 
YURY   (2011-11-29 12:46) [31]

Сергей М., может с точки зрения вашей теории это и глупости, но практика показывает значительное сокращение общего времени выполнения при параллельном запуске нескольких хранимых процедур. Реально:  Последовательное выполнение 12-ти боевых процедур занимает 4,5 часа. Их параллельное выполнение - чуть более полутора часов. Разница очевидна. Проверено многократно на различных наборах хранимок.


 
Сергей М. ©   (2011-11-29 12:47) [32]


> как с помощью этого одного класса реализовать возможность
> параллельного, а также последовательного запуска ХП, в зависимости
> от переданных параметров?


Да не должны вообще об этом заботиться потоки, исполняющие твои ХП !
Их дело - запускать на выполнение указанные им запросы.
А диспетчеризацией должен быть озабочен отдельный поток, если угодно -  доп.поток другого класса или хоть тот же осн.поток.

А у тебя сейчас доп.потоки занимаются совсем несвойственной им работой - шпионят друг за другом в попытке определить свою очередность в этой каше)


 
YURY   (2011-11-29 12:48) [33]

Я не упомянул, что сервер у нас оракловый и пользователей несколько сотен, так что в этом отношении всё нормально.


 
Anatoly Podgoretsky ©   (2011-11-29 12:52) [34]

Зачем же врешь?

ThreadArray[0] := TMyThread.Create(True);

ThreadArray[1] := TMyThread.Create(True);


 
YURY   (2011-11-29 12:53) [35]

Сергей М., Очерёдность у них определена во входных параметрах. Поэтому одни выполняются сразу, а иные попросту ждут завершения других. Никто ни за кем не шпионит. Так все же, как реализовать эту идею в одном классе? Если вернуться к примеру с VCL, то что не так и почему ошибка? Ведь второй поток таки ожидает завершения первого и только потом возникает исключение... Почему оно возникает и как его избежать?


 
Медвежонок Пятачок ©   (2011-11-29 12:55) [36]

запускай на сервере.
нужна асинхронность - запускай через job"ы


 
sniknik ©   (2011-11-29 12:55) [37]

> для сокращения общего времени процесса.
общее время процесса от добавления потоков всегда увеличивается...
http://russian.joelonsoftware.com/Articles/HumanTaskSwitchesConsider.html
параллельность нужна не для этого.


 
YURY   (2011-11-29 12:55) [38]

Anatoly Podgoretsky, почему вру? Что вы имеете в виду?


 
Anatoly Podgoretsky ©   (2011-11-29 12:56) [39]

> YURY  (29.11.2011 12:53:35)  [35]

А у тебя не код, а сплошная ошибка


 
YURY   (2011-11-29 12:58) [40]

sniknik, практика показывает обратное.



Страницы: 1 2 3 вся ветка

Форум: "Начинающим";
Текущий архив: 2012.03.11;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.55 MB
Время: 0.008 c
1-1288777384
ArtemKolesnikov
2010-11-03 12:43
2012.03.11
OLE Word. Как вставить формулу со знаком корня?


2-1322468305
ProgRAMmer Dimonych
2011-11-28 12:18
2012.03.11
Определить, кто освобождает память


15-1321821005
Юрий
2011-11-21 00:30
2012.03.11
С днем рождения ! 21 ноября 2011 понедельник


1-1288366250
Vasena
2010-10-29 19:30
2012.03.11
Полиморфизм+"множественное наследование"


2-1322641073
_qwerty_
2011-11-30 12:17
2012.03.11
работа с bookmark





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский