Параметры в поток

Модераторы: Duncon, Naeel Maqsudov, Игорь Акопян, Хыиуду

Eugie
Сообщения: 708
Зарегистрирован: 17 фев 2004, 23:59
Откуда: SPb

Тут велосипед изобретать не надо, есть стандартное правило: передаваемые в поток данные должны быть валидны по кр.мере на момент входа в потоковую процедуру (а м.б. и до выхода из нее - все зависит от конкретики задачи).
Аватара пользователя
LAngel
Сообщения: 277
Зарегистрирован: 30 мар 2005, 08:19
Откуда: Ульяновск
Контактная информация:

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

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

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

В чем я не прав?
С уважением, Lost Angel...
Eugie
Сообщения: 708
Зарегистрирован: 17 фев 2004, 23:59
Откуда: SPb

Дело в том, что поток запускается не "мгновенно". К моменту, когда управление будет передано потоковой процедуре, ты уже выйдешь из функции, из которой его запускал. А это в частности значит, что ее локальный контекст, или, как еще говорят, фрейм стека, будет разрушен. При этом скорее всего по адресам этих "бывших" локальных переменных окажется просто мусор. А может и не мусор :) , но полагаться на это нельзя.
Evan
Сообщения: 13
Зарегистрирован: 11 июл 2006, 03:42

Очень интересно :) Я поступил по другому: переменная Header стала не string а pchar,а код запуска потока я не менял. Спасибо всем кто откликнулся
Evan
Сообщения: 13
Зарегистрирован: 11 июл 2006, 03:42

Кстати в system.pas функция beginthread описана подобным образом т.е параметр это локальная переменная, а указатель высвобождается в самом потоке. По мойму нет никакой разницы глобальная переменная или локальная - главное что память выделена :) Даже если использовать глобальную переменную в качестве параметра, в потоке все равно Header глючит :)
Eugie
Сообщения: 708
Зарегистрирован: 17 фев 2004, 23:59
Откуда: SPb

Господа, должен признать, что был неправ: конечно же, локальную переменную типа указатель можно передавать в 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;
Всё, надеюсь с этим тонким моментом разобрались :)
Ответить