Страница 2 из 2

Добавлено: 11 июл 2006, 17:02
Eugie
Тут велосипед изобретать не надо, есть стандартное правило: передаваемые в поток данные должны быть валидны по кр.мере на момент входа в потоковую процедуру (а м.б. и до выхода из нее - все зависит от конкретики задачи).

Добавлено: 12 июл 2006, 08:40
LAngel
Eugie, хочется разобраться, почему переменная оказывается разрушена?
Сам часто работаю с потоками и не хочется наступать на грабли, часто пишу вызов подобным образом.

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

Насколько я понимаю, поток создается ещё до завершения функции CreateThread, так именно по этому, я считаю, что ссылка на структуру в памяти будет передана верно.

В чем я не прав?

Добавлено: 12 июл 2006, 15:19
Eugie
Дело в том, что поток запускается не "мгновенно". К моменту, когда управление будет передано потоковой процедуре, ты уже выйдешь из функции, из которой его запускал. А это в частности значит, что ее локальный контекст, или, как еще говорят, фрейм стека, будет разрушен. При этом скорее всего по адресам этих "бывших" локальных переменных окажется просто мусор. А может и не мусор :) , но полагаться на это нельзя.

Добавлено: 15 июл 2006, 23:43
Evan
Очень интересно :) Я поступил по другому: переменная Header стала не string а pchar,а код запуска потока я не менял. Спасибо всем кто откликнулся

Добавлено: 16 июл 2006, 04:34
Evan
Кстати в system.pas функция beginthread описана подобным образом т.е параметр это локальная переменная, а указатель высвобождается в самом потоке. По мойму нет никакой разницы глобальная переменная или локальная - главное что память выделена :) Даже если использовать глобальную переменную в качестве параметра, в потоке все равно Header глючит :)

Добавлено: 18 июл 2006, 19:06
Eugie
Господа, должен признать, что был неправ: конечно же, локальную переменную типа указатель можно передавать в CreateThread(). Главное, чтобы блок памяти, на который она указывает, был валиден на момент входа в потоковую процедуру. Просто я неявно предполагал, что указатель на структуру данных передается в CreateThread() по ссылке (т.е. как var), а это не так. В противном случае предыдущий вывод был бы правильный.
Т.е. можно размещать соответствующую структуру в куче или в статической памяти, но нельзя саму структуру описывать как локальную переменную:

Код: Выделить всё

type 
TThreadParam = record 
...
end; 
PThreadParam = ^TThreadParam; 

var gTp: TThreadParam;

function MyFunc: Cardinal;
var 
  pTp: PThreadParam; 
  lTp: TThreadParam;
begin 
  GetMem(pTp, sizeof(TThreadParam));
  ...
  CreateThread(nil, 0, @GetAsync, pTp, 0, Result); //можно
  CreateThread(nil, 0, @GetAsync, gTp, 0, Result); //можно
  CreateThread(nil, 0, @GetAsync, lTp, 0, Result); //нельзя: локальная переменная lTp будет разрушена к моменту входа в GetAsync()
  ...
end;
Всё, надеюсь с этим тонким моментом разобрались :)