2010-08-13 1 views
2

Я пытаюсь добиться следующего (используя Delphi7): После входа в мою программу пользователь получает контроль, но в фоновом режиме отдельный поток загружает файл из Интернета, чтобы проверить, включен ли текущий лицензионный ключ. Если это так, пользователь получает приглашение, и программа завершается.Некоторая помощь с TThread (Terminate, FreeOnTerminate и другими приключениями в области потоковой передачи)

Итак, я создал отдельный класс TThread, который загружает черный список из сети с помощью InternetOpenURL/InternetReadFile.

Моя проблема заключается в следующем:

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

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

Если я использую FreeOnTerminate: = true, я не могу завершить поток из основного потока. Но в остальном, как я могу сделать поток свободным от его ресурсов после того, как он выполнил свою работу?

Мой другой вопрос:

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

Но как узнать, если пользователь уже закрыл приложение, а программа находится в FormDestroy основной формы, например? Если я синхронизируюсь в неподходящее время, это может привести к нарушениям доступа ...

Спасибо!

+0

Просто любопытно ... почему вы это делаете, а не просто передаете лицензионный ключ, скажем, веб-приложение и получаете ответ «да/нет», чтобы проверить ключ? – GrandmasterB

+0

Я делаю это прямо сейчас. Я вызываю php-скрипт с лицензионным ключом в качестве параметра, и если он занесен в черный список, он возвращает строку BLACKLISTED и причину черного списка (клиент не платил счет и т. Д.) Я также использую тот же скрипт/часть программы для выпуска обновлений лицензий (пользователь обновляет подписку на программное обеспечение) – Steve

+0

Проще говоря, если вы хотите каким-либо образом взаимодействовать с потоком (это включает 'WaitFor' или' Terminate' в особых условиях), тогда 'FreeOnTerminate' не является правильным инструментом для работы. FreeOnTerminate - это ярлык, который вы используете для *** fire-and-forget ***. Вы можете создать 'TSimpleEvent' для отслеживания, когда/если поток фактически уничтожен и пусть ваше приложение' WaitFor'. Но тогда вы могли бы просто уничтожить поток самостоятельно: «Thread.Terminate; Thread.WaitFor (); Thread.Free; '. –

ответ

-1

Я думаю, что это то, что вы пытаетесь сделать ... Назначьте событие OnTerminate() для TThread, которое вызывается как часть вашего основного потока, когда рабочий поток завершается. Вы можете сделать все свои обновления интерфейса (черный список). Создайте свойство рабочего потока, такого как «DownloadComplete», и выполняйте только черный список/проверку, если в событии OnTerminated установлено значение true. Это должно позволить потоку освобождать себя независимо от состояния загрузки, когда программа работает, пока вы.watifor() до выхода программы.

+1

Но таким образом OnTerminate не будет вызываться перед MyThread.Execute заканчивается, правильно? Потому что в MyThread.Execute я загружаю файл - и что произойдет, если загрузка застряла из-за невосприимчивого сервера? MyThread.WaitFor будет продолжать ждать завершения загрузки и приложения зависает ... (я не хочу этого) – Steve

+1

Как вы делаете скачивание? Вы должны иметь возможность отменить его в любой момент, проверив завершенное свойство потока. Хорошая процедура загрузки должна иметь либо тайм-аут, либо обратный вызов, позволяющий вам избавиться от загрузки, если поток отмечен как завершенный. – GrandmasterB

+0

Я использую такой код: http://delphi.about.com/od/internetintranet/a/get_file_net.htm (InternetOpenURL, InternetReadFile) Я думаю, что эти функции имеют значение тайм-аут, но вы не можете отменить их ... – Steve

0

Для второго вопроса не беспокойтесь об обновлении пользовательского интерфейса из потока. Просто установите глобальный флаг. т.е. IsBlackListed: = true; Теперь вы можете использовать этот глобальный флаг в качестве основы для подтасовки пользователя в ответ на какое-то инициированное пользователем действие. Такие, как OnFileSave ... ShowMessage ('Мне бы хотелось сохранить этот файл для вас, но, к сожалению, вы используете черный список.');

IsBlackListed Redux ....

// globally... 
var 
    IsBlackListed : integer; 

... 
initialization 
    IsBlackListed := 0; 

... 
// in your thread: 
if OhMyGodThisIsABlackListedKey then 
    IsBlackListed := 1; 

... Back in the main code, maybe in the OnSaveMyData event: 

if IsBlackListed then 
begin 
    IsBlackListed := -1; // so we don't repeat ourselves 
    MessageBox('Hey, you naughty pirate!'); 
    MyDBConnection.Whatever.DoSQL('insert into licensetable (name,key) values(pirate,blacklisted); 
end; 
+0

Привет! Если ключ занесен в черный список, мне нужно обновить запись в базе данных программы, а компоненты БД находятся в основной форме - поэтому ее необходимо обновить до FormDestroy. Как мне это сделать? – Steve

+0

Пропустить компоненты БД и вставить в черный список (имя пользователя, ключ, бла-бла) значения (yadda yadda); " –

+0

Я уже называю это следующим: MainForm.IBCQuery.SQL.Text: = 'INSERT INTO ...'; Я не могу создать компонент IBCQuery динамически, так как я не хочу делать несколько подключений к базе данных. (и IBCConnection также находится на MainForm) – Steve

1

Во-первых, в вашей проверки объекта потока, создать "заполненный" флаг. Вы можете проверить это верно, чтобы определить, все ли хорошо. Как предлагает Крис Т, пусть поток задан глобальным, чтобы указать, что все хорошо/плохо, так что основной поток может использовать что-то вроде таймера, чтобы проверить это, и что все хорошо или предпринять соответствующие действия.

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

MyThread.Terminate; 
    MyThread.WaitFor; 

И в потоке, проверьте Terminated быть установлен в соответствующих точках. Таким образом, вы можете красиво закрыть.

+0

Я знаю о WaitFor, но если поток заканчивает свое задание до закрытия программы, как он может освобождать свои ресурсы (например, строки, которые он использует), не используя флаг FreeOnTerminate? – Steve