Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Обработчик событий 
:(
    Опции темы
Eminem
Дата 13.2.2012, 11:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 5
Регистрация: 13.2.2012

Репутация: нет
Всего: нет



Hi.
Есть 'долгий' цикл в программе под MFC - синхронная работа с портом, на время его работы замораживается приложение. Что надо сделать в цикле чтобы этого не происходило?
PM MAIL   Вверх
heavix
Дата 13.2.2012, 12:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 60
Регистрация: 10.8.2007

Репутация: нет
Всего: нет



Гуи должен быть в отдельном потоке. Создавай поток, который будет работать с портом.
Почитайте про многопоточность. 

Это сообщение отредактировал(а) heavix - 13.2.2012, 12:32
PM MAIL   Вверх
tzirechnoy
Дата 13.2.2012, 13:03 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1173
Регистрация: 30.1.2009

Репутация: -1
Всего: 16



Надо из цыкла сделать конечный автомат, в котором каждый приход/расход байтов так или иначе ничего не блокирует. Например, с использованием неблокирующихся файловых дескрипторов. Или с помощью аналогов select/waitformultipleobjects. На C проще всего это сделать при помощи switch:

Код

 ca_init(... *ca) {
 ca->state = ST_PASS1;
 };
 ca_process(... *ca) {
 switch (ca->state) {
    case ST_INIT: 
       ca->write_buffer = ...;
       ca->write_size = ...;
       ca->state = ST_WRITE1;
    case ST_WRITE1: 
       if (res = write(ca->port, ca->write_buffer, ca->write_size) < 0) {
            Error ...; Exit();
       } else {
            ca->write_size -= res;
            ca->write_buffer += res;
       };
       if (ca->write_size == 0) {
           ca->read_buffer = ...;
           ca->read_size = 0;
           ca->state = ST_READ1;
       };
       break;
    case ST_READ1:
       if (res = read(ca->port, ca->read_buffer, 100) < 0) {
          Error ...; Exit();
       } else {
          ca->read_size += res;
          ca->read_buffer += res;
       };
       if (check_read_finished(ca->read_buffer, ca->read_size)) {
          ca->state = ST_WRITE2;
          ...
       };
       break;
    case ST_WRITE2: 
        и т.д.
  }
}


 И этот код вызывать периодически -- например, по тому жэ WaitFor или по таймерам или по сообщению о свободном процэссоре.

PS Если то, что я написал кажэтся слишком сложным -- то не следует и пытаться взяться реализовывать это с помощью трэдов -- так сложностей гораздо большэ, и их непонимание приводит к неочевидным нечасто вылазящим косякам, а не просто к тому, что что-то сразу не запускается.
PM MAIL   Вверх
Eminem
Дата 13.2.2012, 14:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 5
Регистрация: 13.2.2012

Репутация: нет
Всего: нет



heavix
Цитата
Гуи должен быть в отдельном потоке. Создавай поток, который будет работать с портом.
Почитайте про многопоточность.


Эм.. У меня есть потоки которые работают непосредственно с портом - один принимает пакеты, другой передает. Порт обращен в сеть RS485 и PC является мастером в этой сети.
Допустим мне надо сформировать сотню пакетов и отправить их в сеть. Можно конечно сформировать сразу все пакеты и зарядить их...
Но сейчас сделано по простому:
Код

for (DWORD bl = 0; bl < ((144 * 1024) / 96); bl++)
{
    m_progres.SetPos(bl);
    pCmd->CMD = COMMAND_WRITE_PM_PAGE;
    ....
    //короче тут формируем пакет
    ....
    pCmd->C.WrPmPage.LenLo = 128;
    memcpy(&pCmd->C.WrPmPage.Data, m_hc.pMemCpu->pMemory[bl]->m_pBuf, 128U);
    //отправляем пакет, но вот ф-ция PacTransmit вернет управление только по получению 
    //ответного пакета от адресуемого устройства или по таймауту 
    if (m_cmt.PacTransmit(TxBuf, 128U + 12, &pAns))
    {
        //здесь смотрим ответ
        if (pAns->ANS == ANSWER_...._PAGE)
        {
    SetLogString(_T("Write error..."));
    //обрабатываем ошибки 
            return FALSE;
        }
    }
    else
    {
        //обрабатываем ошибки 
        return FALSE;
    }
}

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

tzirechnoy
Цитата
Надо из цикла сделать конечный автомат, в котором каждый приход/расход байтов так или иначе ничего не блокирует. Например, с использованием неблокирующихся файловых дескрипторов. Или с помощью аналогов select/waitformultipleobjects. На C проще всего это сделать при помощи switch: 
...
И этот код вызывать периодически -- например, по тому жэ WaitFor или по таймерам или по сообщению о свободном процэссоре.

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


В принципе код мне понятен и идея организовать машину состояний тоже, но не совсем понимаю куда ее вставить. В MFC скрыт superloop, вызывать код периодически по таймерам не эффективно, по сообщению - пока не представляю как сделать. Боюсь что запутаюсь в конце... 

А что есть треды?
  
PM MAIL   Вверх
heavix
Дата 14.2.2012, 12:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 60
Регистрация: 10.8.2007

Репутация: нет
Всего: нет



Можно организовать очередь пакетов. а саму передачу выбросить в отдельный поток. Так же можно организовать стек приема... и слушать порт тоже в отдельном потоке - это если либа которую вы исспользуете для комуникации с портом позволит вам это сделать. Можно писать на чистом api и исспользовать IO_CONTROL ы тогда Вам самому прийдется реализовать протокол обмена (или слямзить чужой и перековырять). Или я просто неправильно понял вопрос? 
PM MAIL   Вверх
Earnest
Дата 14.2.2012, 20:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5962
Регистрация: 17.6.2005
Где: Рязань

Репутация: 87
Всего: 183



Можно, конечно, еще в цикл (после каждой итерации) вставить мини-цикл обработки сообщений (PeekMessage-DispatchMessage), но беда в том, что это не обеспечит полноценной обработки. Такой подход подойдет только если нужно всего-то иметь возможность прервать процесс. 
Так что поток - наилучший выход.
Цитата(Eminem @  13.2.2012,  15:20 Найти цитируемый пост)
А что есть треды?

Думаю, автор имел в виду именно потоки (threads). 
Подход, предложенный tzirechnoy (т.е. квантование операции) - сложнее в смысле избыточности кода - нужно завести массу переменных состояния вместо обычных автоматических. Это неизящно и вообще противоречит мировой гармонии. Иногда так приходится делать по необходимости, но отдельный поток, если это возможно - лучше. Всего-то нужно обеспечить защиту совместных данных и возможность прерывания (если надо) по желанию пользователя. 


--------------------
...
PM   Вверх
Eminem
Дата 14.2.2012, 22:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 5
Регистрация: 13.2.2012

Репутация: нет
Всего: нет



heavix
Цитата
Можно организовать очередь пакетов. а саму передачу выбросить в отдельный поток. Так же можно организовать стек приема... и слушать порт тоже в отдельном потоке - это если либа которую вы исспользуете для комуникации с портом позволит вам это сделать. Можно писать на чистом api и исспользовать IO_CONTROL ы тогда Вам самому прийдется реализовать протокол обмена (или слямзить чужой и перековырять). Или я просто неправильно понял вопрос? 


Это не либа, это мой класс работы с портом. Один поток принимает данные с порта, проверяет легетимность пакета и ложит в FIFO указатель на RAW данные из него. Другой поток занимается отсылкой готовых пакетов (тоже по FIFO). В принципе Ваш первый ответ меня убедил однозначно. Где тут плюсы ставятся.

Earnest
Цитата
Думаю, автор имел в виду именно потоки (threads). 
Подход, предложенный tzirechnoy (т.е. квантование операции) - сложнее в смысле избыточности кода - нужно завести массу переменных состояния вместо обычных автоматических. Это неизящно и вообще противоречит мировой гармонии. Иногда так приходится делать по необходимости, но отдельный поток, если это возможно - лучше. Всего-то нужно обеспечить защиту совместных данных и возможность прерывания (если надо) по желанию пользователя. 


Ну да, треды конечно -  именно потоки. Вообщем мне тоже покзалось что выйдет запутанно со state mashine, хотя можно. Реализовал отдельным потоком. Реальное спасибо всем.  

PS: Хе-хе, а плюсов то не поставить...


Это сообщение отредактировал(а) Eminem - 14.2.2012, 22:11
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Visual C++/MFC/WTL | Следующая тема »


 




[ Время генерации скрипта: 0.0738 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.