Вот вопрос...

Обсуждения по программированию для ОС Windows безотносительно используемого языка программирования. Windows NT, Win32, Windows API, ядро и драйверы.
SLIM
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1840
Зарегистрирован: 04.04.2008 (Пт) 18:21
Откуда: Краснодар

Вот вопрос...

Сообщение SLIM » 13.09.2010 (Пн) 21:58

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

Вот интересно, можно ли как-то "положить" что-нибудь в поток, и чтобы это принадлежало только ему при создании? Ну или после создания.
Пишите жизнь на чистовик.....переписать не удастся.....

BV
Thinker
Thinker
Аватара пользователя
 
Сообщения: 3987
Зарегистрирован: 12.09.2004 (Вс) 0:55
Откуда: Молдавия, г. Кишинёв

Re: Вот вопрос...

Сообщение BV » 14.09.2010 (Вт) 0:12

TLS?
const char *out = "|*0>78-,+<|"; size_t cc = char_traits<char>::length(out);
for (size_t i=0;i<cc;i++){cout<<static_cast<char>((out[i]^89));}cout<<endl;

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: Вот вопрос...

Сообщение Хакер » 14.09.2010 (Вт) 0:13

BV писал(а):TLS?

Да нет, BV, тут несколько иное: шиза над inter-thread communication.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

BV
Thinker
Thinker
Аватара пользователя
 
Сообщения: 3987
Зарегистрирован: 12.09.2004 (Вс) 0:55
Откуда: Молдавия, г. Кишинёв

Re: Вот вопрос...

Сообщение BV » 14.09.2010 (Вт) 1:11

Это прямой ответ на вопрос
SLIM писал(а):Вот интересно, можно ли как-то "положить" что-нибудь в поток, и чтобы это принадлежало только ему при создании? Ну или после создания.

Хакер.
const char *out = "|*0>78-,+<|"; size_t cc = char_traits<char>::length(out);
for (size_t i=0;i<cc;i++){cout<<static_cast<char>((out[i]^89));}cout<<endl;

SLIM
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1840
Зарегистрирован: 04.04.2008 (Пт) 18:21
Откуда: Краснодар

Re: Вот вопрос...

Сообщение SLIM » 14.09.2010 (Вт) 6:29

Блин блин
Спасибо BV, с поиска попал на http://www.wasm.ru/article.php?article=tls и там вначале задаются как раз те вопросы, которые задаю я. Достал пыльного Рихтера, почитаем.
Но, кажется, то что нужно.
Последний раз редактировалось SLIM 14.09.2010 (Вт) 22:17, всего редактировалось 1 раз.
Пишите жизнь на чистовик.....переписать не удастся.....

Twister
Теоретик
Теоретик
Аватара пользователя
 
Сообщения: 2251
Зарегистрирован: 28.06.2005 (Вт) 12:32
Откуда: Алматы

Re: Вот вопрос...

Сообщение Twister » 14.09.2010 (Вт) 8:14

Или я чего-то не понимаю, или вы полезли в какие-то дебри.

И все бы ничего, но передается то указатель на неизвестно что LPVOID. Да и черт бы с ним. Но вот что делать если по данному указателю данные поменялись?
Что мешает передать указатель на данные, которые гарантированно не затрутся? Т.е. выделяем память, пишум туда что нужно, передаём в поток. Поток ими оперирует, а по завершении своей работы освобождает память.
А я все практикую лечение травами...

SLIM
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1840
Зарегистрирован: 04.04.2008 (Пт) 18:21
Откуда: Краснодар

Re: Вот вопрос...

Сообщение SLIM » 14.09.2010 (Вт) 22:12

Ну к примеру я недавно писал планировщика.
Условием было выполнение нескольких задач одновременно - т.е. приложение д.б. многопоточным.
Приложение загружается - шарит файл с описанием каждой задачи. Но запускать на каждую задачу поток - не с руки.
Тогда я сделал следующим образом - при получаю информацию в массив структур, потом запускаю один поток, который постоянно просматривает каждый элемент этого массива. Смотрит он на следующее время запуска задачи. И вот, если время наступило - создаем для задачи и пускаем ее в свободное выполнение в другом потоке. Тем временем текущий поток дальше проверяет задачи. И тут он опять обнаруживает звенящую задачу, и опять создает поток. Ну и т.д.
Что же передать в поток каждой задачи? Ну как минимум нужно передать индекс в массиве. Он же - некий итератор. Но передаем мы его адрес. Ну и получается, что значение переменной-итератора меняется быстрее чем поток скопирует его значение к себе в локальную переменную. Это чревато тем что запустится совсем не та задача, или несуществующая задача.
В итоге получается что при создании потока мы должны подождать пока можно дальше проверять массив.
Ну примерно так.
Вот что тогда делать?
Пишите жизнь на чистовик.....переписать не удастся.....

Twister
Теоретик
Теоретик
Аватара пользователя
 
Сообщения: 2251
Зарегистрирован: 28.06.2005 (Вт) 12:32
Откуда: Алматы

Re: Вот вопрос...

Сообщение Twister » 15.09.2010 (Ср) 8:14

Я не пойму, почему нельзя в поток передать индекс в массиве? Массив что, может измениться (может добавиться или удалиться элемент) за время создания потока? Если что-то там удаляется, то да, индекс собъется. В этом случае тебе необходимо просто завести булеву галочку в структуре (deleted_bool), а не удалять её из массива. Это легче всего, хотя есть и другие способы, например, синхронизация доступа к массиву из разных потоков.

Но передаем мы его адрес. Ну и получается, что значение переменной-итератора меняется быстрее чем поток скопирует его значение к себе в локальную переменную.
Я не знаю на чём ты пишешь и как, но могу сказать одно: какое число ты передашь в lpParameter функции CreateThread, то и ляжет на стек при вызове процедуры потока. Т.е. проблемы вообще нет никакой, если пользоваться нормальными методами. Я бы сделал примерно так:

Код: Выделить всё
CloseHandle(CreateThread(
                          nil,
                          0,
                          @ThreadProc, // Адрес процедуры потока
                          pointer(your_array_index), // Кастуем любое передавамое значение к типу pointer и передаём
                          0,
                          nil
                        ));

...

procedure ThreadProc(lpVoid: pointer); stdcall;
var
  MyIndex: integer;
begin
// Получаем значение на стеке, кастуем к integer
MyIndex := integer(lpVoid);
end;
А я все практикую лечение травами...

SLIM
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1840
Зарегистрирован: 04.04.2008 (Пт) 18:21
Откуда: Краснодар

Re: Вот вопрос...

Сообщение SLIM » 15.09.2010 (Ср) 20:05

Я наверное не так объяснил
Давай поэтапно
1. В неком потоке запускается бесконечный цикл, где проверяется каждая задача и сравнивается следующее время запуска с текущим.
2. Как только очередная задача будет допущена к выполнению - создается поток. В поток передаем индекс. Точнее не индекс, а указатель на индекс. У меня - это переменная i, которая прирастает на 1 в цикле for перебора элементов массива. Передали - но приложение медленно создает поток и переменная i уже приросла. И получается что по адресу i уже не то значение которое мы передавали когда создавали поток задачи.

Второй вариант. Представь такую ситуацию.
Работает во всю WindowProc, у которого стоит обработчик нажатия кнопки на форме. В этом обработчике стоит формирование какой-то строки, потом вызывается функция, которая создает еще одно окно (у которого тоже есть winproc). При создании окна ты должен написать caption в - ту саму строку, которую ты формировал. И передаем мы адрес этой строки в функцию.
Так вот пока в функции формирования нового окна дойдет до копирования с переданного адреса строки - этой строки уже не будет (оконная процедура обрабатывает другое сообщение, а строка была локальной.
Это тупой пример - так плохо писать. Он придуман мной прям сейчас, просто для того чтобы ярко показать
Пишите жизнь на чистовик.....переписать не удастся.....

Twister
Теоретик
Теоретик
Аватара пользователя
 
Сообщения: 2251
Зарегистрирован: 28.06.2005 (Вт) 12:32
Откуда: Алматы

Re: Вот вопрос...

Сообщение Twister » 16.09.2010 (Чт) 7:21

Я тебя понял прекрасно. И уже показал в примере, что надо передавать не указатель на счётчик цикла, а само значение счётчика. В чём проблема-то?
А я все практикую лечение травами...

Александр Дмитриев
Бывалый
Бывалый
Аватара пользователя
 
Сообщения: 296
Зарегистрирован: 05.01.2005 (Ср) 3:39
Откуда: Санкт-Петербург    Куда: /dev/null

Re: Вот вопрос...

Сообщение Александр Дмитриев » 16.09.2010 (Чт) 10:40

Twister писал(а):надо передавать не указатель на счётчик цикла, а само значение счётчика

Возможно, предложу усовершенствование идеи: надо передавать не указатель на счётчик цикла, а сразу указатель на элемент массива: &array[array_index].
Википедия — это наилучший источник информации по теме «Википедия».

Twister
Теоретик
Теоретик
Аватара пользователя
 
Сообщения: 2251
Зарегистрирован: 28.06.2005 (Вт) 12:32
Откуда: Алматы

Re: Вот вопрос...

Сообщение Twister » 16.09.2010 (Чт) 11:44

Да без разницы, от этого ничего не поменяется.
А я все практикую лечение травами...

Александр Дмитриев
Бывалый
Бывалый
Аватара пользователя
 
Сообщения: 296
Зарегистрирован: 05.01.2005 (Ср) 3:39
Откуда: Санкт-Петербург    Куда: /dev/null

Re: Вот вопрос...

Сообщение Александр Дмитриев » 16.09.2010 (Чт) 12:13

Да конечно не поменяется, просто, по-моему, так меньше изврата.
Википедия — это наилучший источник информации по теме «Википедия».

SLIM
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1840
Зарегистрирован: 04.04.2008 (Пт) 18:21
Откуда: Краснодар

Re: Вот вопрос...

Сообщение SLIM » 16.09.2010 (Чт) 23:06

Twister писал(а):Я тебя понял прекрасно. И уже показал в примере, что надо передавать не указатель на счётчик цикла, а само значение счётчика. В чём проблема-то?

Я когда увидел что ты передаешь _не_ указатель - надеялся что это все таки ошибка. Просто не совсем знаю дельфовый.
Можно ли передавать индекс вместо указателя? Да, можно. Но мне кажется это ужасто некрасиво.
И здесь Александр Дмитриев прав на все сто, передавать нужно именно адрес конкретного элемента массива, и логично предположить что массив - глобален, раз его можно юзать с разных потоков.
Но ладно с этим примером - он имеет какое-никакое решение.

А вот пример с окном (который второй) меня немного притормозил самого. Что же передавать если нужно передать строку (массив). Только указатель. И что тогда будешь делать?
Пишите жизнь на чистовик.....переписать не удастся.....

Twister
Теоретик
Теоретик
Аватара пользователя
 
Сообщения: 2251
Зарегистрирован: 28.06.2005 (Вт) 12:32
Откуда: Алматы

Re: Вот вопрос...

Сообщение Twister » 20.09.2010 (Пн) 8:10

Можно ли передавать индекс вместо указателя? Да, можно. Но мне кажется это ужасто некрасиво.
Вам шашечки или ехать?

Тут необходимо понимать, почему единственный аргумент, который принимает на себя процедура потока, имеет тип "указатель". Просто зачастую в поток необходимо передавать больше одного входного dword'а, либо блок данных заранее неизвестной длины. И это логично: мы передаём указатель на данные, т.к. передавать их все через стек не всегда возможно/рационально. Но как быть, если нам нужно передать всего один dword? Лично мне кажется, что передавать указатель на него - вот это действительно некрасиво.

Что же передавать если нужно передать строку (массив). Только указатель. И что тогда будешь делать?

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

ЗЫ. ИМХО, проблема высосана тобой из ничего. Чуток стоит подумать, не дольше минуты, и решение придёт само собой.
А я все практикую лечение травами...

SLIM
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1840
Зарегистрирован: 04.04.2008 (Пт) 18:21
Откуда: Краснодар

Re: Вот вопрос...

Сообщение SLIM » 20.09.2010 (Пн) 12:58

Twister писал(а):Но как быть, если нам нужно передать всего один dword? Лично мне кажется, что передавать указатель на него - вот это действительно некрасиво.

Ну позволю себе не согласиться. Все таки указатель - это указатель. И передавать вместо адреса какое-то значение...ну не верно это на мой взгляд.
Представь твой код попадет другому программисту. И тут он решает изменить ф-ю потока. Он ведь думает что передан указатель, начинает читать по этому указателю - а облом. Мало того что там может быть хлам - так может еще и быть ошибка нарушения доступа. Да, не спорю, когда выхода нет, можно так поступить. Но повторюсь - не сторонник таких способов.
Twister писал(а):Я и про это уже говорил. Передавать указатель на те данные, которые гарантированно не изменятся.

Т.е. откажись от динамичности кода. Если какая-то строка будет формироваться динамично, в процессе выполнения кода, и я не буду знать сколько таких строк будет - ну что вот тогда делать? Это хорошо если я знаю что у меня 10 строк - могу создать буфер для каждой. Но вот с тем же вторым примером - я понятия не имел сколько может быть сформировано строк. Резервировать память на большее количество строк? На 100? На 1000? Сколько считать оптимальным?
Плохо это все.
По поводу TLS - это все же не то. Поэтому способа кроме синхронизации двух потоков не существует.
Twister писал(а):ЗЫ. ИМХО, проблема высосана тобой из ничего. Чуток стоит подумать, не дольше минуты, и решение придёт само собой.

Ну так скажем да, проблема придумана и надумана. Мелкая - но мне было интересно, можно ли ее как-то решить более простым способом. Почему бы это и не пообсуждать?
Пишите жизнь на чистовик.....переписать не удастся.....

iGrok
Артефакт VBStreets
Артефакт VBStreets
 
Сообщения: 4272
Зарегистрирован: 10.05.2007 (Чт) 16:11
Откуда: Сетевое сознание

Re: Вот вопрос...

Сообщение iGrok » 20.09.2010 (Пн) 13:47

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

А насчёт строк.. Ну выделяй под них память динамически, в чём проблема-то? sysallocstring и всё. Ну или globalalloc. Только за памятью следить не забывай.
label:
cli
jmp label

Twister
Теоретик
Теоретик
Аватара пользователя
 
Сообщения: 2251
Зарегистрирован: 28.06.2005 (Вт) 12:32
Откуда: Алматы

Re: Вот вопрос...

Сообщение Twister » 20.09.2010 (Пн) 13:55

Ну позволю себе не согласиться. Все таки указатель - это указатель.

На уровне процессора на стек ложится один dword, процессору пофиг в каком контексте используется это значение, он вообще не знает смысл этого числа. Типизация этого несчастного dword'а нужна лишь программисту и компилятору, да и то, знаешь, чисто формально. Если бы ты писал на асме, к примеру, тебе тоже, как и процессору, было бы пофиг на то, указатель это или просто число. Впрочем, это дело вкуса. Мой способ сэкономит как минимум одну ассемблерную инструкцию, код будет быстрее и меньше (если передаём индекс, разумеется). ;)

Представь твой код попадет другому программисту. И тут он решает изменить ф-ю потока. Он ведь думает что передан указатель, начинает читать по этому указателю - а облом
Что это за программист такой, который изменит функцию потока, не посмотрев, что в неё передаётся? Не надо приводить настолько надуманные примеры. Ну а уж если вам встретится такой программист, то следует гнать его подальше! :)

Вообще, такие вещи как комментарии придуманы не зря. И в сложных для понимания местах кода их просто необходимо расставлять. Если пользоваться их услугами, то никаких коллизий не должно возникать. Погляди на мой пример. Я чётко указал что я передаю в поток и что получаю в потоке. Разве что-то осталось неясным? Если к этому еще и добавить говорящие названия переменных (что, по сути, я тоже сделал), то такой код врядли кто-то сможет упрекнуть в нечитабельности или в сложности для понимания.

Т.е. откажись от динамичности кода. Если какая-то строка будет формироваться динамично, в процессе выполнения кода, и я не буду знать сколько таких строк будет - ну что вот тогда делать?
Блин. Вот ты опять куда-то не туда полез. Какая потеря? Какой динамичности? О чём ты вообще?

Задача: передать в поток указатель на данные. Данные по указателю могут измениться, нам же нужно гарантированно их доставить.
Решение: выделяем память; копируем туда все необходимые данные; создаём поток; передаём указатель на выделенную нами память; в потоке ловим указатель; по окончании работы с данными [или по завершению потока] освобождаем память.

Что тут могло вызвать затруднения? :roll:
А я все практикую лечение травами...

Twister
Теоретик
Теоретик
Аватара пользователя
 
Сообщения: 2251
Зарегистрирован: 28.06.2005 (Вт) 12:32
Откуда: Алматы

Re: Вот вопрос...

Сообщение Twister » 20.09.2010 (Пн) 13:56

Ё-моё, iGrok, краткость сестра таланта ;)

Всё то же самое написал, только на порядок короче :)
А я все практикую лечение травами...

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: Вот вопрос...

Сообщение Хакер » 20.09.2010 (Пн) 14:11

Twister писал(а):Что тут могло вызвать затруднения? :roll:

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

Когда такого понимания нет, нет и понимания того, как же это какой-то участок памяти не может вдруг случайно поменяться (ещё бы: ведь никто не отвечает за память, она безхозна...).
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

Twister
Теоретик
Теоретик
Аватара пользователя
 
Сообщения: 2251
Зарегистрирован: 28.06.2005 (Вт) 12:32
Откуда: Алматы

Re: Вот вопрос...

Сообщение Twister » 20.09.2010 (Пн) 14:17

Ты как всегда радикален в высказываниях :lol:
А я все практикую лечение травами...

SLIM
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1840
Зарегистрирован: 04.04.2008 (Пт) 18:21
Откуда: Краснодар

Re: Вот вопрос...

Сообщение SLIM » 20.09.2010 (Пн) 15:54

Twister писал(а):Задача: передать в поток указатель на данные. Данные по указателю могут измениться, нам же нужно гарантированно их доставить.
Решение: выделяем память; копируем туда все необходимые данные; создаём поток; передаём указатель на выделенную нами память; в потоке ловим указатель; по окончании работы с данными [или по завершению потока] освобождаем память.

То ли я реально чего-то не доганяю, то ли неправильно объясняю.
Я объясняю что после того как я выделю память, наполню ее чем-то, передам указатель на нее в поток - эта память не только может содержать не то, ее может вообще не быть вовсе.
Вот поэтапно. Пусть это будет некая ф-я, которая создает поток в свою очередь.
1. Резервируем кусок памяти
2. Заполняем его чем-то
3. Создаем поток, передаем указатель на память.
4. Все, работа ф-ии окончена. Все что выделялось в ф-ии разрушено и более не существует и никому не нужно.
Так вот, пока система создаст поток, по указателю уже совсем не то что мы передавали - функция то уже завершилась, а поток еще работать не начал.

Давай на конкретных примерах.
Задача: есть некий цикл с итерационной переменно i. На каждом шаге формируется строка с текстом "Это шаг " + i, создается поток, а в него передается указатель на строку. Далее две ветки задачи - ты не знаешь предел i, т.е. ты не знаешь сколько потоков будет и сколько строк в них передадут. Или ты знаешь все это.
Далее. Функция потока, получив указатель на строку, печатает ее в MessageBox - е. и завершается.

Это выглядит примерно так.
Код: Выделить всё
int _tmain(int argc, _TCHAR* argv[])
{
   HANDLE hThread = NULL;
   LPTSTR pszMsg = NULL;
   LPTSTR pszNum = NULL;

   pszNum = (LPTSTR)calloc(sizeof(TCHAR)*10, sizeof(TCHAR));
   for (int i=0; i<4; i++)
   {
      pszMsg = (LPTSTR)calloc(sizeof(TCHAR)*255, sizeof(TCHAR));
      
      wcscpy(pszMsg, L"Это шаг ");
      _itow(i, pszNum, 10);
      wcscat(pszMsg, pszNum);

      hThread = CreateThread(NULL, 0, ThreadkExecFn, pszMsg, 0, NULL);
      CloseHandle(hThread);
      hThread = NULL;
      free(pszMsg);
   }

   free(pszNum);

   MessageBox(NULL, L"конец", L"конец", MB_OK);
   return 0;
}


И функция потока

Код: Выделить всё
DWORD WINAPI ThreadkExecFn(LPVOID pvParam)
{
   MessageBox(NULL, (LPTSTR) pvParam, L"Сообщение", MB_OK);
   return 0;
}



А теперь не проверяя такой код, как думаешь, что будет выводить в сообщение функция потока?
Второй вопрос - как гарантированно доставить потоку нужные данные?
Третий вопрос. Пусть сейчас я знаю что у меня будет четыре потока, я могу глобально буферизировать 4 строки и передавать разные указатели. А если я не знаю сколько потоков будет, и строки должны быть объявлены локально.

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

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: Вот вопрос...

Сообщение Хакер » 20.09.2010 (Пн) 16:00

SLIM писал(а):4. Все, работа ф-ии окончена. Все что выделялось в ф-ии разрушено и более не существует и никому не нужно.
Так вот, пока система создаст поток, по указателю уже совсем не то что мы передавали - функция то уже завершилась, а поток еще работать не начал.

У, блин, да ты трудный. Тебе говорят не разрушать и не освобождать память в конце функции. Подчёркнутый фрагмент из цитаты должен не быть истинным.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

SLIM
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1840
Зарегистрирован: 04.04.2008 (Пт) 18:21
Откуда: Краснодар

Re: Вот вопрос...

Сообщение SLIM » 20.09.2010 (Пн) 16:03

Хакер писал(а):У, блин, да ты трудный. Тебе говорят не разрушать и не освобождать память в конце функции. Подчёркнутый фрагмент из цитаты должен не быть истинным.

С функцией неудачный пример. Лучше рассмотреть что что я написал
Пишите жизнь на чистовик.....переписать не удастся.....

Twister
Теоретик
Теоретик
Аватара пользователя
 
Сообщения: 2251
Зарегистрирован: 28.06.2005 (Вт) 12:32
Откуда: Алматы

Re: Вот вопрос...

Сообщение Twister » 20.09.2010 (Пн) 16:05

4. Все, работа ф-ии окончена. Все что выделялось в ф-ии разрушено и более не существует и никому не нужно.
Прочувствуй разницу между выделением памяти (о котором я говорил) и резервированием её на стеке. ;)
А я все практикую лечение травами...

SLIM
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1840
Зарегистрирован: 04.04.2008 (Пт) 18:21
Откуда: Краснодар

Re: Вот вопрос...

Сообщение SLIM » 20.09.2010 (Пн) 16:11

Twister писал(а):Прочувствуй разницу между выделением памяти (о котором я говорил) и резервированием её на стеке. ;)
Хакер писал(а):У, блин, да ты трудный. Тебе говорят не разрушать и не освобождать память в конце функции. Подчёркнутый фрагмент из цитаты должен не быть истинным.

Вы предлагаете передавать указатель и переложить высвобождение памяти по этому указателю на поток?
Пишите жизнь на чистовик.....переписать не удастся.....

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: Вот вопрос...

Сообщение Хакер » 20.09.2010 (Пн) 16:13

SLIM писал(а):С функцией неудачный пример. Лучше рассмотреть [url]что что[/url] я написал

Что-что ты написал?

Кажется ты написал вот это:
SLIM писал(а):Это выглядит примерно так.
Код: Выделить всё
    int _tmain(int argc, _TCHAR* argv[])
    {
       HANDLE hThread = NULL;
       LPTSTR pszMsg = NULL;
       LPTSTR pszNum = NULL;

       pszNum = (LPTSTR)calloc(sizeof(TCHAR)*10, sizeof(TCHAR));
       for (int i=0; i<4; i++)
       {
          pszMsg = (LPTSTR)calloc(sizeof(TCHAR)*255, sizeof(TCHAR));
         
          wcscpy(pszMsg, L"Это шаг ");
          _itow(i, pszNum, 10);
          wcscat(pszMsg, pszNum);

          hThread = CreateThread(NULL, 0, ThreadkExecFn, pszMsg, 0, NULL);
          CloseHandle(hThread);
          hThread = NULL;
          free(pszMsg);
       }

       free(pszNum);

       MessageBox(NULL, L"конец", L"конец", MB_OK);
       return 0;
    }

    DWORD WINAPI ThreadkExecFn(LPVOID pvParam)
    {
       MessageBox(NULL, (LPTSTR) pvParam, L"Сообщение", MB_OK);
       return 0;
    }



А теперь правильный ответ:
Код: Выделить всё
    int _tmain(int argc, _TCHAR* argv[])
    {
       HANDLE hThread = NULL;
       LPTSTR pszMsg = NULL;
       LPTSTR pszNum = NULL;

       pszNum = (LPTSTR)calloc(sizeof(TCHAR)*10, sizeof(TCHAR));
       for (int i=0; i<4; i++)
       {
          pszMsg = (LPTSTR)calloc(sizeof(TCHAR)*255, sizeof(TCHAR));
         
          wcscpy(pszMsg, L"Это шаг ");
          _itow(i, pszNum, 10);
          wcscat(pszMsg, pszNum);

          hThread = CreateThread(NULL, 0, ThreadkExecFn, pszMsg, 0, NULL);
          CloseHandle(hThread);
          hThread = NULL;
          // free(pszMsg); // FIXED: Идиотизм
       }

        free(pszNum)

       MessageBox(NULL, L"конец", L"конец", MB_OK);
       return 0;
    }

    DWORD WINAPI ThreadkExecFn(LPVOID pvParam)
    {
       MessageBox(NULL, (LPTSTR) pvParam, L"Сообщение", MB_OK);
       free(pvParam); // FIXED: Надо здесь
       return 0;
    }
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: Вот вопрос...

Сообщение Хакер » 20.09.2010 (Пн) 16:17

SLIM писал(а):Вы предлагаете ... переложить высвобождение памяти по этому указателю на поток?

На кого угодно, хоть на Папу римского. Главное это делать после того, как поток скажет «окей, парни, я прочёл данные из буфера, можете его освобождать».

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

Но крайний идиотизм — освобождать память сразу же после выделения.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

SLIM
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1840
Зарегистрирован: 04.04.2008 (Пт) 18:21
Откуда: Краснодар

Re: Вот вопрос...

Сообщение SLIM » 20.09.2010 (Пн) 16:19

Все, теперь я вас понял.
FIXED: Я дубина.
Пишите жизнь на чистовик.....переписать не удастся.....

SLIM
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1840
Зарегистрирован: 04.04.2008 (Пт) 18:21
Откуда: Краснодар

Re: Вот вопрос...

Сообщение SLIM » 29.09.2010 (Ср) 22:26

Созрел дополнительный вопрос, более менее связанный с текущим, поэтому тему новую не создавал.
Есть библа, написаная на VC++.
Я пробую ее заюзать в Builder-е.
В библиотеке есть экспортируемые функции, которые возвращают указатели на массив символов (строку). Соответственно функция под строки выделяет память. Но делается это в библиотеке. Соответственно память нужно когда-то и отдавать. Кто будет чистить память? Может ли этим заниматься Builder? Ведь для выделения памяти например использовались функции сишной библиотеки, где гарантия что Builder их знает и корректно почистит память? А вдру это будет не Builder, а Delphi, тот вообще сишных функций не знает. Что делать в такой ситуации?
Первое что пришло на ум - это создать массив указателей на строку в библиотеке при выделении новой памяти. При выделении памяти - заносить этот указатель в очередное "свободное" место в массиве. Экспортировать из библиотеки функцию, которая за раз очистит всю память, на которую указывают все эти указатели и переводить их в свободное состояние. Тогда тут куча проблем. Массива может не хватить, тогда придется его расширять, тогда, если не хватит места в том участке памяти (где находится массив указателей) - придется его перемещать в другое свободное место, способное уместить весь массив и т.д.

Может есть какие-то штатные средства в Builder-е? Например AnsiString можно присвоить указатель на строку, и вроде как должно само следиться за памятью - когда надо очищать. Но тогда еще хуже. Например есть какие-то данные, указатели на которые передаются без выделения памяти в функции, которая должна вернуть указатель, а где-то в другом месте, и удалять\менять это строку просто так нельзя, соответственно и удалять без спроса тоже нельзя.

В общем такая проблема. Может я ее тоже конечно надумал, но все же, направьте если можно.


И еще два мааленьких вопроса по Builder-у, которые не могу отискать из-за неправильной возможно формиулировке
1.На форме есть какой-то ЭУ. Как сослаться на него из внешней функции, например в другом модуле? Например в каком-то событии это легко, а вот из вне...
2. Почему не могу объявить указатель на функцию типа LPTSTR (*pfnSomeFun)(int iSomeParam);? Приходится объявлять void* (*pfnSomeFun)(int iSomeParam); и потом кастовать где нужно


UPD::Первую проблему решил
Пишите жизнь на чистовик.....переписать не удастся.....

След.

Вернуться в Windows-программирование

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 0

    TopList  
cron