| 
 
 
 
 Легенда:
  новое сообщение 
  закрытая нитка 
  новое сообщение 
  в закрытой нитке 
  старое сообщение   | 
Напоминаю, что масса вопросов по функционированию форума снимается после прочтения его описания.
Новичкам также крайне полезно ознакомиться с данным документом.
| [C++] Как запустить в программе паралельный поток обработки данных?  07.11.03 20:21   [Ktirf] Автор: CrazyPitbull Статус: Незарегистрированный пользователь
 |  
| Проблема такая, программа обрабатывает данные и одновременно с обработкой должна быть возможность работы с интерфейсом... Как это сделать? Насколько я понимаю необходимо запустить новый поток для обработки данных, тогда программа висеть не будет? Пишу в Builder'e. Если можно посмотреть исходники какие или есть дока по данной теме буду очень благодарен. Заранее спасибо! |  
|  | [C++] Поиск по форуму тоже рулит...  08.11.03 09:09 Автор: HandleX <Александр М.> Статус: The Elderman
 |  
| >    Проблема такая, программа обрабатывает данные и > одновременно с обработкой должна быть возможность работы с
 > интерфейсом... Как это сделать? Насколько я понимаю
 > необходимо запустить новый поток для обработки данных,
 > тогда программа висеть не будет? Пишу в Builder'e. Если
 > можно посмотреть исходники какие или есть дока по данной
 > теме буду очень благодарен. Заранее спасибо!
 
 Потоки дело сурьёзное...
 Часто выгода от них призрачная...
 Если нужно, чтобы интерфейс приложения не висел во время обработки данных, тебе может помочь Application->ProcessMessages().
 
 Пример (на Delphi, но ты поймёшь, imho)
 
 
procedure TForm1.Button1Click(Sender: TObject);
begin
  If Button1.Tag <> 0 Then
  Begin
    Button1.Tag := 0;
    Exit;
  End;
  Button1.Caption := 'Stop';
  Repeat
    Button1.Tag := Button1.Tag + 10;
    Caption := IntToStr(Button1.Tag);
    Application.ProcessMessages;
    sleep(100);
  Until Button1.Tag = 0;
  Button1.Caption := 'Start';
  Caption := '0';
end;
 Суть примера поясняю — эдакий старт-стоповый таймер на одной кнопке с циклом обработки без потоков ;-) Ключевой элемент, используемый для отсановки обработки - поле TButton.Tag. В принципе, можно завести глобальную переменную под это дело.
 
 Смотри тута. Читай все ветки ;-)
 |  
|  |  | не очень я люблю ProcessMessages  08.11.03 09:36 Автор: Killer{R} <Dmitry> Статус: Elderman
 |  
| С ним всякие глюки иногда бывают не очень понятные и если его засунуть в неудачное место может получится его рекурсивный вызов самого себя. Я обычно делаю BeginThread (с CreateThread могут быть проблемы с работой с динасический памятю из разных потоков) затем ставлю оюработчик сообщений на какоенить окно и свойства VCL'ных объектов из потоков меняю вызовом SendMessage у которого wParam - код функции а lParam -указатель на структуру параметров. Затем обертываю весь обработчик в try..catch и если у юзера вылетел глюк то ему показывается что где и когда. |  
|  |  |  | Ну как-бы гибкость тоже должна быть ;-)  08.11.03 09:50 Автор: HandleX <Александр М.> Статус: The Elderman
 |  
| > С ним всякие глюки иногда бывают не очень понятные и если > его засунуть в неудачное место может получится его
 > рекурсивный вызов самого себя. Я обычно делаю BeginThread
 > (с CreateThread могут быть проблемы с работой с
 > динасический памятю из разных потоков) затем ставлю
 > оюработчик сообщений на какоенить окно и свойства VCL'ных
 > объектов из потоков меняю вызовом SendMessage у которого
 > wParam - код функции а lParam -указатель на структуру
 > параметров. Затем обертываю весь обработчик в try..catch и
 > если у юзера вылетел глюк то ему показывается что где и
 > когда.
 Я про простые случаи имел ввиду.
 Пусть автор поста знает все возможные варианты...
 В потоках тоже могут быть всякие трудновоспринимаемые глюки... Особенно если учесть, что TForms и прочие гуевые библиотеки плохо переносят многопоточность. С использованием TThread тоже достаточно гемора можно поймать.
 
 Короче, всё это на любителя. Пусть автор поста станет гибче в своих решениях и знает про все фичи.
 |  
|  |  |  |  | Ну так SendMessage как раз против глюков в потоках  08.11.03 09:57 Автор: Killer{R} <Dmitry> Статус: Elderman
 |  
| > Я про простые случаи имел ввиду. > Пусть автор поста знает все возможные варианты...
 Ну да в принципе если ему просто построить график какой нибудь то ProcessMessages самое то
 > В потоках тоже могут быть всякие трудновоспринимаемые
 > глюки... Особенно если учесть, что TForms и прочие гуевые
 > библиотеки плохо переносят многопоточность.
 SendMessage посылает сообщение основному потоку и ждет завершения его обработки - и глюков никаких. Правда конечно не совсем красиво вызывать какуюто другую функцию которая к примеру добавляет TListItem через SendMessage зато не глючит
 |  
|  |  |  |  |  | Ok.  08.11.03 10:08 Автор: HandleX <Александр М.> Статус: The Elderman
 |  
|  |  
|  | [C++] Все таки RTFM рулит  08.11.03 00:53 Автор: amirul <Serge> Статус: The Elderman
 |  
| >    Проблема такая, программа обрабатывает данные и > одновременно с обработкой должна быть возможность работы с
 > интерфейсом... Как это сделать? Насколько я понимаю
 Насколько я помню, как раз цикл GetMessage/DispatchMessage как раз и запускается отдельным тредом (по крайней мере так в MFC, в vcl скорее всего тоже), в основном (который WinMain) же можно делать что угодно. Если же действительно нужен новые тред, то нужно отнаследоваться от класс TThread (кажется так) и переопределить виртальную функцию Execute. Тогда по new TMyThread будет создаваться поток, исполняющий данную функцию, в деструкторе (delete) он будет уничтожаться.
 
 Кроме того, как уже упоминалось советую CreateThread.
 
 > можно посмотреть исходники какие или есть дока по данной
 > теме буду очень благодарен. Заранее спасибо!
 Дока - это билдеровский хелп.
 
 ЗЫ: Насколько я понимаю, если возник вопрос по созданию потоков, следующий вопрос будет по их синхронизации. Сразу отвечу, что тема эта достаточно обширная и помочь может только тщательный RTFM
 Основные виды синхронизации:
 1) Разделяемая память: ну это понятно. Контекст памяти у разных потоков для одного процесса один, так что никаких дополнительных извращений не надо
 2) Event-ы (события): CreateEvent и сопутствующие - за дополнительной инфой в MSDN
 3) Mutex-ы (mutually exclusive - взаимно исключающие) CreateMutex и остальные, описание в MSDN
 4) Semaphore-ы (семафоры) CreateSemaphore ...
 5) Named Pipe-ы (именованные потоки) CreateNamedPipe (CreateFile тоже умеет их создавать) ...
 
 Кроме того, если все таки воспользуешься TThread-ом советую посмотреть в описание его member-функций. Я его юзал давно (лет 5 назад), но что то такое там точно есть
 |  
|  |  | [C++] Неплохо... но как переопределить Execute?  08.11.03 15:24 Автор: CrazyPitbull Статус: Незарегистрированный пользователь
 |  
| Вроде наплохо с TThread'oм работать. Я отнаследовал создал свою функцию оюработки, но немогу переопределить Execute, нужно передать указатель на мою функцию или что? |  
|  |  |  | [C++] Просто переопределить  08.11.03 16:49 Автор: amirul <Serge> Статус: The Elderman
 |  
| > Вроде наплохо с TThread'oм работать. Я отнаследовал создал > свою функцию оюработки, но немогу переопределить Execute,
 > нужно передать указатель на мою функцию или что?
 В vcl записано примерно следующее
 
 class TThread {
 //...
 protected:
 void Execute(аргументы);
 };
 
 void TThread::Execute(аргументы) {
 // stub
 }
 
 Ты делаешь
 class TMyThread {
 protected:
 virtual void Execute(аргументы);
 };
 
 void TMyThread::Execute(аргументы) {
 // Здесь тело твоего потока (функция, которая будет исполняться в новом потоке)
 }
 
 Главное следи, чтобы типы аргументов совпадали, иначе ты не переопределишь, а перегрузишь (читай введешь еще одну функцию) функцию Execute.
 
 А вообще почитай про работу с виртуальными функциями.
 |  
|  |  |  |  | [C++] Так и сделал, но иногда глючит...  09.11.03 02:33 Автор: CrazyPitbull Статус: Незарегистрированный пользователь
 |  
| Так и сделел, вроди работает, если  не трогать окно программы, а если поработать с интерфейсом, то после завершения задачи выкидывает исключение... |  
|  |  |  |  |  | А вот для работы с интерфейсом у TThread есть метод Synchronize  09.11.03 09:44 Автор: Killer{R} <Dmitry> Статус: Elderman
 |  
| Который реализован через SendMessage. Нельзя из других потоков обращаться к VCL компонентам, будут именно такие глюки. В хелпе кстати об этом написано. |  
|  |  |  |  |  |  | А через указатель тож никак?  09.11.03 12:24 Автор: CrazyPitbull Статус: Незарегистрированный пользователь
 |  
| Вот какая досада, как раз нужно обращаться к одному из компанентов... Чтож делать? Мож обойти как можно или есть какий хитрый счпособ?  Я пробовал в отнаследованном классе создавать указатель на компонент, а в конструкторе пихал в него адрес того к которому нужно обратиться, но  опять вылетает исключение! |  
|  |  |  |  |  |  |  | А через указатель тож никак?  09.11.03 13:05 Автор: Killer{R} <Dmitry> Статус: Elderman
 Отредактировано 09.11.03 13:18  Количество правок: 3
 |  
| Во первых прежде чем закрывать свою прогу надо остановить поток. Во вторых я не очень понял что именно ты хочешь обходить хитрым  способом и при чем тут указатель? Там вроде везде к VCL классам обращение через указатели делается. Просто если хочешь изменить например текст в каком нибудь EditBox'е то вызываешь в Synchronize процедуру которая его меняет и все. |  
|  |  |  |  |  |  |  |  | А через указатель тож никак?  10.11.03 15:36 Автор: CrazyPitbull Статус: Незарегистрированный пользователь
 |  
| Я о другом, когда программа работает, если я буду работать с интерфейсом, то когда я из процесса обращаюсь к одному из компонентов, вылетает исключение, это нужно делать через Sinhronise? если да, то как? |  
|  |  |  |  |  |  |  |  |  | А хелпы читать гордость мешает?  10.11.03 17:45 Автор: Killer{R} <Dmitry> Статус: Elderman
 |  
| Цитирую: This example shows how to call a button’s click method in a thread-safe manner:
 
 void __fastcall TMyThread::PushTheButton(void)
 
 {
 Button1->Click();
 }
 
 void __fastcall TMyThread::Execute()
 {
 ...
 Synchronize(PushTheButton);
 ...
 }
 |  
|  |  |  |  | А мона еще проще  08.11.03 17:37 Автор: Killer{R} <Dmitry> Статус: Elderman
 |  
| File->New->Other->Thread Object хотя имхо BeginThread еще проще Ж) |  
|  |  | [C++] Все таки RTFM рулит  08.11.03 02:16 Автор: void <Grebnev Valery> Статус: Elderman
 |  
| > Кроме того, если все таки воспользуешься TThread-ом советую > посмотреть в описание его member-функций. Я его юзал давно
 > (лет 5 назад), но что то такое там точно есть
 
 Совершенно точно. Сам я юзал тоже давно. Но вроде всё получалось в BCB++.
 
 А в части примеров(квуик старт), см. в папке
 C:\Program Files\Borland\CBuilder6\Examples\Apps\Threads
 
 PS. Я б стал копать API, позже, когда бы увител что класса TThread от BCB++
 уже недостаточно.
 |  
|  | [C++] Ключевые слова - threads, multithreading  07.11.03 22:11 Автор: Ktirf <Æ Rusakov> Статус: Elderman
 |  
| Можно также посмотреть документацию на WinAPIшный вызов CreateThread (и его близких родственников). |  
|  |  | [C++]  CreateThread  - это оно и есть.  10.11.03 20:13 Автор: vagrant Статус: Незарегистрированный пользователь
 |  
| CreateThread  - это оно и есть. У меня так работает счетная программа для моделирования полимеризации, сделанная из Buildera. Могу для примера привести кусочек.
 
 По кнопочке запускается обработчик
 void __fastcall TRCDesk::btStartProcessClick(TObject *Sender)
 {
 if(Indicator==0)
 {btStartProcess->Enabled=false; Indicator=1;
 btKillProcess->Enabled=true;   IndRotation=1;
 //-----------------------------------------------------------------
 RIVTr1=CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) ReactorIV_Thread,
 (LPVOID)NULL, THREAD_SUSPEND_RESUME, &Tid);
 lstEvent=CreateEvent(NULL,false,false,"lst");    lst=1; ltime_ind=0;
 //-------------------------------------------------------------------
 btLife->Enabled=true;
 AttrX = GetSystemMetrics(SM_CXFULLSCREEN);
 AttrY = GetSystemMetrics(SM_CYFULLSCREEN);
 TrackBarX->Position=-alphaVolume;
 TrackBarY->Position=-betaVolume;
 TrackBarZ->Position=-gammaVolume;
 sc=long(float(AttrY)/1.732/float(L.x));
 
 };
 }
 
 котрый и запускает процесс ReactorIV_Thread
 
 DWORD ReactorIV_Thread(LPVOID param);
 DWORD Tid;
 HANDLE RIVTr1; HANDLE lstEvent;
 
 DWORD
 ReactorIV_Thread(LPVOID param)
 {
 ...здесь все вычисления
 }
 
 если надо убить процес, запускаем функцию TerminateThread(RIVTr1,NULL);
 
 Работает все надежно, как лопата.
 Весь интерфейс и визуализация - снаружи потока.
 |  
|  |  |  | А в лопате есть потенциальный баг  11.11.03 01:42 Автор: Killer{R} <Dmitry> Статус: Elderman
 |  
| CreateThread в билдере лучше не юзать а вместо него юзать BeginThread. И кстати что означает - "Весь интерфейс и визуализация - снаружи потока."? |  
 
 
 |  |