реклама на сайте
подробности

 
 
2 страниц V  < 1 2  
Reply to this topicStart new topic
XVR
сообщение Nov 18 2008, 06:45
Сообщение #16


Гуру
******

Группа: Свой
Сообщений: 3 123
Регистрация: 7-04-07
Из: Химки
Пользователь №: 26 847



Цитата(hadrov @ Nov 18 2008, 02:14) *
Ага, теперь понял откуда ноги ростут. Эта процедура из TThread. При создании модуля с классом TThread и написано, что нельзя рисовать из потока, кроме как используя метод synchronize. Позже попробую написать его потомок, а пока я потоки реализованы с помощью API. В этом случае есть возможность рисовать из потока в главном окне?

Что бы не действовать методом научного тыка приведу краткий алгоритм, а то не уверен, что правильно Вас понял.

Поток приема из УАРТа.
Код
1. Ждем стартовый байт. (WaitCommEvent(), WaitForSingleObject())
2. Входим в критическую секцию. (EnterCriticalSection())
3. Записываем данные в буфер. (ReadFile())
4. Выходим из критической секции. (LeaveCriticalSection())
5. Устанавливаем событие в сигнальное состояние (событие с автосбросом) (SetEvent())
6. Переходим к п. 1.


Поток обработки данных
Код
1. Ждем наступления события. (WaitForSingleObject())
2. Входим в критическую секцию.
3. Извлекаем данные из буфера.
5. Выходим из критической секции.
6. Переходим к п. 1.
Да, именно так



Цитата
И как после извлечении данных из буфера и выхода из критической секции вставить пункт "Рисуем в главном окне", чтобы он отработал нормально?
Посадить потоки на TThread, или вручную реализовать то, что сделано в TThread::Synchorize. А именно -
  1. Данные помещаются в очередь (можно просто переменная)
  2. Главному окну посылается специальное сообщение (любое)
  3. WaitForSingleObject(sync_event)
В обработчике специального сообщения главного окна:
  1. Забираем данные, рисуем
  2. SetEvent(sync_event)
Event sync_event должен быть создан как

Код
  sync_event=CreateEvent(NULL,FALSE,FALSE,NULL);
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Nov 18 2008, 07:40
Сообщение #17


фанат дивана
******

Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684



Цитата(hadrov @ Nov 18 2008, 04:14) *
Поток приема из УАРТа.
...


Не так.
Поток приема из УАРТа.
  1. Ждем стартовый байт. (WaitCommEvent(), WaitForSingleObject())
  2. Входим в критическую секцию. (EnterCriticalSection()) - не надо, больше никто всё равно не читает из порта.
  3. Записываем данные в буфер. (ReadFile())
  4. Выходим из критической секции. (LeaveCriticalSection())
  5. Распределяем память под принятое количество байтов и копируем туда принятое;
  6. Отправляем указатель на этот блок памяти в главное окно при помощи PostMessage(WM_USER+3);
  7. Устанавливаем событие в сигнальное состояние (событие с автосбросом) (SetEvent()) - это тоже лишнее, поскольку мы отправили сообщение сразу в главное окно и никто не спит, дожидаясь данных.
  8. Переходим к п. 1.

Основной поток программы:
  1. Ждем сообщения WM_USER+3;
  2. Берём данные из указателя - параметра, отрисовываем их.
  3. Уничтожаем память под указателем.
  4. Переходим к п. 1.


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post
XVR
сообщение Nov 18 2008, 09:25
Сообщение #18


Гуру
******

Группа: Свой
Сообщений: 3 123
Регистрация: 7-04-07
Из: Химки
Пользователь №: 26 847



Цитата(AHTOXA @ Nov 18 2008, 10:40) *
Не так.
Поток приема из УАРТа.
  1. Ждем стартовый байт. (WaitCommEvent(), WaitForSingleObject())
  2. Входим в критическую секцию. (EnterCriticalSection()) - не надо, больше никто всё равно не читает из порта.
  3. Записываем данные в буфер. (ReadFile())
  4. Выходим из критической секции. (LeaveCriticalSection())
  5. Распределяем память под принятое количество байтов и копируем туда принятое;
  6. Отправляем указатель на этот блок памяти в главное окно при помощи PostMessage(WM_USER+3);
  7. Устанавливаем событие в сигнальное состояние (событие с автосбросом) (SetEvent()) - это тоже лишнее, поскольку мы отправили сообщение сразу в главное окно и никто не спит, дожидаясь данных.
  8. Переходим к п. 1.
Основной поток программы:
  1. Ждем сообщения WM_USER+3;
  2. Берём данные из указателя - параметра, отрисовываем их.
  3. Уничтожаем память под указателем.
  4. Переходим к п. 1.
Частые заказы/освобождения блоков памяти череваты возростанием фрагментации кучи, что может привести к перерасходу памяти и общим тормозам для всей программы. Все таки рекомендуется сделать кольцевой буффер.

Да, и делать 2 дополнительных потока это тоже перебор, вполне хватит и одного - для приема. Обработку и отрисовку можно делать в главном потоке приложения.
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Nov 18 2008, 09:46
Сообщение #19


фанат дивана
******

Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684



Цитата(XVR @ Nov 18 2008, 14:25) *
Частые заказы/освобождения блоков памяти череваты возростанием фрагментации кучи, что может привести к перерасходу памяти и общим тормозам для всей программы. Все таки рекомендуется сделать кольцевой буффер.


Ерунда. Не те объёмы. Да и блоки скорее всего фиксированной длины.

Цитата(XVR @ Nov 18 2008, 14:25) *
Да, и делать 2 дополнительных потока это тоже перебор, вполне хватит и одного - для приема. Обработку и отрисовку можно делать в главном потоке приложения.


Ну а я как написал?


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post
hadrov
сообщение Nov 18 2008, 10:32
Сообщение #20


Участник
*

Группа: Участник
Сообщений: 15
Регистрация: 11-11-08
Пользователь №: 41 540



Цитата(AHTOXA @ Nov 18 2008, 13:46) *
Ну а я как написал?

Скорее всего, это адресовалось мне.


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

Т.к. следующее предположение верно
Цитата
Да и блоки скорее всего фиксированной длины.
, то можно ведь изменить пункт
Цитата
# Распределяем память под принятое количество байтов и копируем туда принятое;

на "один раз выделили в начале и потом просто пользуемся этим указателем до конца работы".

Попутно вопрос: сейчас данные приходят через фиксированные промежутки времени, данные успевают обработаться за это время, и поэтому, как я понимаю, хватает одной ячейки во втором буфере. А теперь представим ситуацию, когда данные приходят нерегулярно. Тут уже потребуется FIFO с достаточным количеством ячеек?
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Nov 18 2008, 11:03
Сообщение #21


фанат дивана
******

Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684



Цитата(hadrov @ Nov 18 2008, 15:32) *
Я сейчас сделал еще один тестовый вариант с использованием компоненты TComPort. Там нечто подобное внутри реализовано - крутится поток и при приеме данных возникает событие, данные сохраняются в буфере.


Да, это как раз очень подходящий пример.

Цитата
Т.к. следующее предположение верно, то можно ведь изменить пункт "Распределяем память под принятое количество байтов и копируем туда принятое;"
на "один раз выделили в начале и потом просто пользуемся этим указателем до конца работы".


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

Цитата
Попутно вопрос: сейчас данные приходят через фиксированные промежутки времени, данные успевают обработаться за это время, и поэтому, как я понимаю, хватает одной ячейки во втором буфере. А теперь представим ситуацию, когда данные приходят нерегулярно. Тут уже потребуется FIFO с достаточным количеством ячеек?


В винде никогда нельзя закладываться на то, что программа успеетsmile.gif


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post
hadrov
сообщение Nov 18 2008, 11:20
Сообщение #22


Участник
*

Группа: Участник
Сообщений: 15
Регистрация: 11-11-08
Пользователь №: 41 540



Цитата
Нет, так нельзя.
Теперь ясно. Я не так понял "Распределяем память под принятое количество байтов и копируем туда принятое". Почему то подумал, что это всегда будет одна и та область памяти. А тут мы каждый раз выделяем новую, но при этом указатели на старые куски данных могут быть еще валидными. Ну, и таким образом отпал вопрос о не успевании программы.
Go to the top of the page
 
+Quote Post
defunct
сообщение Dec 23 2008, 02:09
Сообщение #23


кекс
******

Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326



Цитата(hadrov @ Nov 12 2008, 13:55) *
Вот где бы почитать о таких фичах, а то подобные вещи мелькают либо в FAQ'ах или приходят интуитивно, что так делать не стоит.

На форуме мастеров делфи. http://www.delphimaster.ru/
Go to the top of the page
 
+Quote Post

2 страниц V  < 1 2
Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 23rd June 2025 - 00:03
Рейтинг@Mail.ru


Страница сгенерированна за 0.0144 секунд с 7
ELECTRONIX ©2004-2016