Главная страница
    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, практика показывает обратное.


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


> сервер у нас оракловый


А что, Оракл разве не позволяет запуск запросов на выполнение в неблок.режиме ?
Я просто не в курсе ..


> Очерёдность у них определена во входных параметрах


Да нашиша передавать параметром "очередность"-то ?
Зачем заставлять рабочие потоки выполнять несвойственную им задачу диспетчеризации ?


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

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

Ну и в чем тогда проблема?
Если практика показывает, значит процедуры ты уже запускал из под потоков.
Так?
Так.
Тогда в чем же проблема?


 
sniknik ©   (2011-11-29 13:01) [43]

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


 
sniknik ©   (2011-11-29 13:03) [44]

> значит процедуры ты уже запускал из под потоков.
скорее из под процессов, но не говорит... а там параллельность от ядер "включается".


 
Anatoly Podgoretsky ©   (2011-11-29 13:03) [45]

> YURY  (29.11.2011 12:55:38)  [38]

Вот ты запустил два потока и ничего тебе не помешало.


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


> Медвежонок Пятачок ©   (29.11.11 13:00) [42]


Не запускал он их)
Похоже он запустил несколько экземпляров клиентских процессов (на одном хосте или на разных - не суть как важно), дал каждому из них команду выпониль такую-то свою ХП и замерил время, за которое все эти процессы получат результаты своих запросов.


 
YURY   (2011-11-29 13:04) [47]

Медвежонок Пятачок, действительно запустил. Параллельно. И они отлично работают. Гораздо быстрее, чем последовательно. Но в том и суть, что не все они должны запускаться параллельно, а чать из них - строго после окончания других. Это как идти в магазин, говоря по телефону и кушая мороженое - три дпроцедуры. Но совершить покупку (четвёртая процедура) можно лишь по окончании процедуры прихода в магазин.


 
Anatoly Podgoretsky ©   (2011-11-29 13:05) [48]

> YURY  (29.11.2011 12:58:40)  [40]

Моя практика и мониториг тоже показывает обратно, видно как потоки за
процессор дерутся и это не бесплатно.


 
YURY   (2011-11-29 13:05) [49]

Сергей М., совершенно верно.


 
Anatoly Podgoretsky ©   (2011-11-29 13:09) [50]

> sniknik  (29.11.2011 13:01:43)  [43]

Сервер или запросы не в порядке


 
YURY   (2011-11-29 13:10) [51]

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


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

Ну если запускал, то включаем голову и думаем:

Что мы имеем?
Что надо сделать?

Имеем 20 хранимок.
1. Из них 10 можно запускать независимо от всего.
2. 3 процедуры нужно выполнить последовательно, причем первая из них - стартует независимо от всех других
3. Остальные тоже друг за другом, первая тоже независимо от всех.

Итого:

Нужно 10 + 2 потоков, в которые передаются списки процедур.
В первых десяти список будет из одного элемента.
В двух последних списки будут из трех и семи элементов.

запускаем потоки, потоки перебирают списки и запускают хранимки.

Все!


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


> Anatoly Podgoretsky ©   (29.11.11 13:05) [48]


Ну тут некий выигрыш в произ-ти параллельно выполняемых сервером запросов возможно произрастает из врЕменного кеширования сервером многократно используемых клиентскими запросами наборов данных.


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

> YURY  (29.11.2011 13:10:51)  [51]

Вместо того чтобы поискать где бутылочное горло, решил сделать велосипед с
трехугольными колесами


 
Anatoly Podgoretsky ©   (2011-11-29 13:17) [55]

> Сергей М.  (29.11.2011 13:11:53)  [53]

Судя по его описанию, у него чего то не в порядке.
А кеширование происходит и используется независимо от потоков.
Конечно я делаю все чтобы это произошло.


 
YURY   (2011-11-29 13:18) [56]

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


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

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

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


он начинает сразу проектировать некие абстрактные потоки, которые никак не отвечают поставленной задаче.
Оказывается эти потоки нужно диспетчеризировать.
А диспетчера нет.
Поэтому костыль в виде вайтфор и прочего.

В то время как решение [52] - на поверхности лежит и руками машет.


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

Медвежонок Пятачок, проблема в том, что заранее я не знаю сколько хранимок,

1. Заранее знать не надо.
Надо обработать выбор юзера, что он там себе навыбирал.
Затем осмыслить его и формализовать.


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

Бил гейтц, когда писал свой инет проводник, тоже не знал, пойдешь ли ты на мастера делфи его программой.
Однако же написал его и он даже ходит на мастера делфи.


 
YURY   (2011-11-29 13:24) [60]

Anatoly Podgoretsky, тощущение, что мы друг друга не понимаем ) Давайте так. Хранимка А выполняется за 15 минут. Хранимка Б за 40. При последовательном запуске обоих хранимок общее время выполнения 55 минут. При параллельном (используя потоки) - 40 минут 5 секунд. Имеем выигрыш во времени 14 минут 55 секунд. Это реальные данные. Вообще же хранимок несколько десятков и их количество увеличивается со временем.


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

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

Нужен ОДИН класс потока.

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

PS Чернилами для седьмого класса можно писать и в первом и в седьмом и в десятом классах.
И даже на пенсии можно писать чернилами для седьмого класса.


 
sniknik ©   (2011-11-29 13:34) [62]

> При параллельном (используя потоки) - 40 минут 5 секунд.
т.е. вопрос решен? потоки работают.

или
> Имеем выигрыш во времени 14 минут 55 секунд.
делим шкуру не убитого медведя?

вообще ИМХО, вот это
> что не все они должны запускаться параллельно, а чать из них - строго после окончания других.
наводит на мысль что потоки вообще не нужны...
нужен ассинхронный режим, с, у некоторых, в "онкомплит" запуском еще одного выполнения.


 
YURY   (2011-11-29 13:37) [63]

Медвежонок Пятачок, в реальности поток один и он простейший.

type
 TMyThread = class(TThread)
 private
   { Private declarations }
 public
   _ADOQuery     : TADOQuery;
   _Connection   : TADOConnection;
   _ProcedureName: String;
   _Tag          : Longint;
   Msg           : String;
   ReturnValue   : Integer;
 protected
   procedure Execute; override;
 end;

implementation

procedure TMyThread.Execute;
var
 i: Integer;
begin
 with TADOStoredProc.Create(nil) do
 try
   CommandTimeout := 0;
   CursorLocation := clUseServer;
   Connection     := _Connection;
   ProcedureName  := _ProcedureName;
   Parameters.Refresh;
   Parameters.ParamValues["@Msg"] := "";

   for i := 0 to Parameters.Count - 1 do
     if (Parameters.Items[i].Direction = pdInput) and
        (_ADOQuery.Locate("f_ProcName;f_ParamName",
               VarArrayOf([ProcedureName, Parameters.Items[i].Name]), [])) and
        (not _ADOQuery.FieldByName("f_Value").IsNull) then
       Parameters.Items[i].Value := _ADOQuery.FieldValues["f_Value"];

   ExecProc;

   Msg := Parameters.ParamValues["@Msg"];
   ReturnValue := Parameters.ParamValues["@Return_Value"];
 finally
   Free;
 end;
end;

Осталось только научить его ожидать завершения другого потока этого же класса, если таковое действие необходимо (узнает он об этом через какой-нибудь признак во входных параметрах). Но вот научить не получается - ошибка та же, что и в первоначально приведённом примере с VCL...


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

Осталось только научить его ожидать завершения другого потока этого же класса,

Не, это клиника.
Лучше научи своего кота программировать.
У него быстрее получится.


 
sniknik ©   (2011-11-29 13:41) [65]

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


 
Сергей М. ©   (2011-11-29 13:44) [66]


> Осталось только научить его ожидать завершения другого потока


Ты чего какой настырный ?)

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

with TADOStoredProc.Create(nil) do
try
  CommandTimeout := 0;
  CursorLocation := clUseServer;
  Connection     := _Connection; // ждут тебя здесь грабли, ибо коннекшн создан у тебя совсем в другом потоке


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

TMyThread = class(TThread)
private
  { Private declarations }
 _ADOQuery     : TADOCommand;
 _Connection   : TADOConnection;
public
  _ProcNames: TStrings;


 
YURY   (2011-11-29 13:47) [68]

Я потому и обратился сюда, ибо, видимо, не умею программировать. Умел бы - сделал бы без вопросов. Но никто так и не указал где конкретно ошибка и почему она происходит. Не поняв этого, я еще долго буду биться в пустых Сизифовых попытках. Но в любом случае спасибо тем, кто указывает на мои глупости и неумения. Было бы хуже, если бы попросту проигнорировали.


 
DiamondShark ©   (2011-11-29 13:48) [69]


> Но никто так и не указал где конкретно ошибка и почему она происходит.

Ты троль.


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

// ждут тебя здесь грабли, ибо коннекшн создан у тебя совсем в другом потоке

Да не, это у него так, - для примера, для простоты.
А на самом деле реальный код совсем другой и он идеален и совершенен.


 
YURY   (2011-11-29 13:50) [71]

Сергей М., граблей не наблюдается. Я привёл реально работающий поток, который прекрасно показывает себя при параллельной работе нескольких десятков хранимок в бою.


 
sniknik ©   (2011-11-29 13:50) [72]

> А абитражом должен заниматься совсем другой поток, тот самый который заведует общим списком заданий.
нафига? если уж выбирать такой путь (тупой если честно), то ничего не нужно дополнительно, просто в поток нужно передавать не 1 значение на выполнение, а список, и пусть "крутится" пока список не кончился. одно там выполнение, или два, или десяток подряд неважно, все решается анализом (из БД?) и подготовкой перед "на выполнение".


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

Я привёл реально работающий поток, который прекрасно показывает себя при параллельной работе нескольких десятков хранимок в бою.

Все!
Остановись и ничего не трогай!
Пусть так и работает.


 
Сергей М. ©   (2011-11-29 13:55) [74]


> никто так и не указал где конкретно ошибка и почему она
> происходит


Она происходит потому что :

if Assigned(ptrThread) then // это условие всегда истинно
// в этот момент другой поток потенциально завершает свое выполнение и убивает сам себя, ибо FreeOnTerminate = True
 ptrThread^.WaitFor; // а здесь ты получаешь граблями, потому как обращаешься к трупу


 
Anatoly Podgoretsky ©   (2011-11-29 13:58) [75]

> YURY  (29.11.2011 13:18:56)  [56]

Какие выберет не знаешь, но откуда то знаешь какие при этом параметры
указывать. Странно это.


 
Anatoly Podgoretsky ©   (2011-11-29 14:02) [76]


> YURY   (29.11.11 13:47) [68]

Сними очки или позови кота, мы ему все еще раз объясним.


 
Anatoly Podgoretsky ©   (2011-11-29 14:02) [77]


> Медвежонок Пятачок ©   (29.11.11 13:48) [70]

Кривые примеры нам не нужны


 
Anatoly Podgoretsky ©   (2011-11-29 14:05) [78]

Чувствую, что скоро придется тему закрывать из-за бесперктивности или посылать в Потрепаться.


 
YURY_   (2011-11-29 14:08) [79]

Anatoly Podgoretsky, список параметров хранимок я получаю сам, а значения параметров пользователь задаёт через интерфейс. Эти значения я считываю запросом. В только что приведённом рабочем потоке видно, как эти значения отыскиваются в зависимости от имени хранимки и заполняют её параметры.


 
YURY_   (2011-11-29 14:11) [80]

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


 
Кщд   (2011-11-29 14:12) [81]

YURY   (29.11.11 13:50) [71]
dbms_scheduler решает Вашу задачу


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


> sniknik ©   (29.11.11 13:50) [72]
>  то ничего не нужно дополнительно, просто в поток нужно
> передавать не 1 значение на выполнение, а список


А список-то это кто будет формировать, Пушкин ?)
Его поток-арбитр и должен сформировать)
И с элементами этого списка так или иначе должны быть ассоциированы предварительно созлданные объекты синхронизации, которыми поток, получивший список, будет руководствоваться при принятии решения где ему подождать, а где он может сразу приступить к выполнению элемента


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

но по какой-то причине не происходит возобновление работы второго потока.

а его кто-то приостанавливал?
им обоим resume сделали.


 
YURY_   (2011-11-29 14:16) [84]

Медвежонок Пятачок, WaitFor и приостановил.


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


> почему к трупу?


Потому что 1-й поток, которого 2-й будет ожидать, к моменту вызова 2-м потоком метода WaitFor запросто может успеть убить себя, закрыв при этом свой хэндл.  Что собссно и происходит, потому как сообщение "Thread error: Неверный дескриптор (6)" именно об этом тебе и сигнализирует.


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

Приостанавливает суспенд. Вайтфор не приостанавливает ни разу.


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


> WaitFor и приостановил


Не успел)
Тот кого ты собрался ждать по  WaitFor, к этому моменту уже отбыл в мир иной, так что никакой приостановки не было)


 
YURY_   (2011-11-29 14:20) [88]

Сергей М., в данном случае я на форме наюлюдаю несколько секунд, как меняются значения в Edit1 от 0 до 20000 и только после этого происходит исключение. Если же WaitFor убрать, то оба потока стартуют одновременно и те же несколько секунд я наблюдаю изменение значений в обоих TEdit.


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

закройте уже тему, а?


 
YURY_   (2011-11-29 14:24) [90]

Медвежонок Пятачок, а вот тут сказано, что приостанавливает: "Попросту говоря, когда поток А вызывает метод WaitFor потока B, сам он приостановливается, пока поток B не завершится. "
http://forum.vingrad.ru/forum/topic-60076.html#st_0_view_0


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

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

Что дальше?


 
YURY_   (2011-11-29 14:27) [92]

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


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

закройте тему, а?

/* украина, политика, путин, газ, власти скрывают, нло, киркоров родил дочь от суррогатных матери и отца..... */


 
sniknik ©   (2011-11-29 14:29) [94]

> почему происходит ошибка.
потому что ты дебил, иного объяснения при куче ответов/объяснений на эту тему не вижу.


 
YURY_   (2011-11-29 14:30) [95]

Медвежонок Пятачок, если такая функция выполняется внутри потока, то она не приостанавливает поток - он выполняется в виде этой самой функции. Разве не так?


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


> и только после этого происходит исключение


Так я ж тебе дважды нарисовал картину маслом почему оно происходит)
Что опять не понятно-то ?


 
sniknik ©   (2011-11-29 14:33) [97]

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


 
YURY_   (2011-11-29 14:33) [98]

sniknik, ну зачем на личности переходить? Лучше бы аргументировали. Ваше предположение о том, что первый поток завершился к моменту вызова WaitFor во втором потоке я опровергнул. Можете сами проверить - 1 минута времени требуется. Значит, дело в другом. Но в чём?


 
sniknik ©   (2011-11-29 14:34) [99]

> А список-то это кто будет формировать, Пушкин ?)
основной, там дел то будет на полсекунды...


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


> "Попросту говоря, когда поток А вызывает метод WaitFor потока
> B, сам он приостановливается, пока поток B не завершится "


А если поток A вызывает WaitFor уже ПОСЛЕ того как поток B успел завершиться и уничтожить следы своего бытия, поток A при этом ничего не ждет - он немедля закругляется, сформировав перед этим отлуп ""Thread error: Неверный дескриптор (6)"


 
sniknik ©   (2011-11-29 14:37) [101]

> Значит, дело в другом. Но в чём?
вот тут то и пригодится "переход на личности", т.к. рзумные доводы ты проигнорировал, а опровержения какие то не убедительные, из твоих же фантазий, а не реальности.


 
YURY_   (2011-11-29 14:37) [102]

Сергей М., суть моего ответа в посте 98


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

Медвежонок Пятачок, если такая функция выполняется внутри потока, то она не приостанавливает поток - он выполняется в виде этой самой функции. Разве не так?

функция WaitFor у тебя внутри потока. Возврат из нее не сразу. Пока нет возврата, следующий код стоит.

функция formatdatetime тоже внутри потока может быть вызвана. Возврат из нее не сразу. Пока нет возврата следующий код стоит.

И чего?


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


> предположение о том, что первый поток завершился к моменту
> вызова WaitFor во втором потоке я опровергнул


Да нифига ты его не опроверг.
Именно это и происходит - никакая иная ситуация в приведенном коде не может привести к ошибке с кодом 6.


 
YURY_   (2011-11-29 14:41) [105]

sniknik, Фантазии не причём. Есть пример с VCL (первый мой пост) и на его основе нетрудно убедиться, что дело вовсе не в том, что первый поток успевает завершиться до старта WaitFor второго. 1 минута времени для проверки. Но можно, конечно, попинять на фантазии человека, если нет идей. Тоже вариант.


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

Не обижайте вы пацана.
Ему и так кот в отладчик нассал.


 
sniknik ©   (2011-11-29 14:43) [107]

> и на его основе нетрудно убедиться
убеждаемся..
> FreeOnTerminate := True;
ой...
кранты убеждениям.


 
YURY_   (2011-11-29 14:44) [108]

Сергей М., а вы попробуйте запустить пример. Увеличьте, скажем, значение 20000 на порядок. И убедитесь, что несколько минут второй поток терпеливо ожидает завершения первого. И как только он завершается - происходит исключение. Или вы полагаете, что второй поток несколько минут не стартует после Resume?


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

procedure TForm1.Button1Click(Sender: TObject);
var
ThreadArray: Array of TMyThread;

К моменту выполнения магического кода внутри потоков массив уже мертв.
Дундук!


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

А если бы он был жив, то настал бы черед замечаний приведенных выше.


 
YURY_   (2011-11-29 14:49) [111]

Медвежонок Пятачок, почему массив мертв? Он умрет тогда, когда закроется главная форма. Не так ли?


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

Медвежонок Пятачок, почему массив мертв? Он умрет тогда, когда закроется главная форма. Не так ли?

твой массив умрет сразу после :

....
ThreadArray[0].Resume;
ThreadArray[1].Resume;
end;


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


> дело вовсе не в том, что первый поток успевает завершиться
> до старта WaitFor второго


Дело именно в этом - сколько раз еще тебе это повторить чтобы ты наконец это понял ?)

Специально для фомы лениво-неверующего, не желающего прошарить исх-к WaitFor:

procedure TMyThread.Execute;
begin
if Assigned(ptrThread) then
 try
   ptrThread^.WaitFor;
 except
  on e: Exception do
    MessageBox(0, PChar(e.Message), "ГРАБЛИ", mb_ok);    
 end;

MessageBox(0, "Ты никогда не увидишь это сообщение, потому что FreeOnTerminate = True", "НЕТ ГРАБЛЕЙ", mb_ok);    
for i := j to k do
  ptrEdit^.Text := IntToStr(i);
end;


 
sniknik ©   (2011-11-29 14:53) [114]

> Увеличьте, скажем, значение 20000 на порядок.
время там не причем... оно в потоке УЖЕ и сразу прошло проверку
if Assigned(ptrThread) then
и ждет в WaitFor;, того момента, когда
> FreeOnTerminate := True;
второй поток будет разрушен.


 
Anatoly Podgoretsky ©   (2011-11-29 14:54) [115]

> YURY_  (29.11.2011 14:20:28)  [88]

Тебе повторить чтоли OnTerminate


 
YURY_   (2011-11-29 14:55) [116]

Медвежонок Пятачок, да, согласен. Ну пусть умирает. Он в данном примере не важен. Ок, массив умер. Но потоки-то живы! Им до этого массива дела нет. Так?


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

Да у него вообще не тот код работает что приведен здесь.

Смотрите выше.
Есть массив - локальная переменная процедуры баттон1клик.
Есть код потоков, которые обращаются к полям масива.
Но нигде нет ни передачи массива, ни одноименных полей потоков.

А массив помирает сразу после выхода из баттон1клик.

Этот нехороший человек просто парит нам моск.


 
app ©   (2011-11-29 14:56) [118]

Закрыто за безперспективностью



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

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

Наверх





Память: 0.77 MB
Время: 0.005 c
15-1321384309
Faceless
2011-11-15 23:11
2012.03.11
Работа Delphi программистом в США


15-1322026771
И. Павел
2011-11-23 09:39
2012.03.11
Скиньте, пожалуйста, mc.exe


15-1321220394
KilkennyCat
2011-11-14 01:39
2012.03.11
TCanvas &amp; HTML


6-1253185020
bvv
2009-09-17 14:57
2012.03.11
Проблема с потоками сканирования


2-1322507312
_qwerty_
2011-11-28 23:08
2012.03.11
работа с таблицей бд из класса





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
Английский Французский Немецкий Итальянский Португальский Русский Испанский