Russian Qt Forum
Ноябрь 26, 2024, 00:33 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: 1 2 [3] 4   Вниз
  Печать  
Автор Тема: Опять потоки!  (Прочитано 27357 раз)
BRE
Гость
« Ответ #30 : Июнь 07, 2009, 14:10 »

Я так понял, что ты хочешь примерно такого (псевдокод!):

Код
C++ (Qt)
class B : public QObject
{
Q_OBJECT
public:
void readFromNode(int nodeAddress, int startDataAddress, int quantityData);
void writeToNode(int nodeAddress, int startDataAddress, int quantityData , QByteArray &data);
void pollingNodes();
};
 
class ThreadRead : public QThread
{
Q_OBJECT
public:
ThreadRead( B *cb, int nodeAddress, int startDataAddress, int quantityData ) :
 m_cb( cb ), m_nodeAddress( nodeAddress ), m_startDataAddress( startDataAddress ), m_quantityData( quantityData )
{
}
 
protected:
void run()
{
m_cb->readFromNode( nodeAddress, startDataAddress, quantityData );
}
 
private:
B *m_cb;
int m_nodeAddress;
int m_startDataAddress;
int m_quantityData
}
 
void A::m_readData( int nodeAddress, int startDataAddress, int quantityData, ... )
{
ThreadRead *th = new ThreadRead( cb, nodeAddress, startDataAddress, quantityData );
th->start();
}
 
Объект класса В используется один общий или создается для каждой операции свой?
Класс B должен быть написан с условием того, что его методы могут быть вызваны из разных потоков одновременно!

Мне как-то это все не очень нравиться, по моему нужно еще подумать над архитектурой.  Улыбающийся
Я не очень понял что должно происходить с флагом manual и что требуется от pooling'a (необходимо его запихнуть в отдельную нить или он может вызываться из главной нити по таймеру?).
Записан
kuzulis
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2812


Просмотр профиля
« Ответ #31 : Июнь 07, 2009, 17:01 »

Цитировать
Объект класса В используется один общий или создается для каждой операции свой?
объект класса один общий (например последовательный порт, на котором сидят на RS-485 куча узлов с разными адресами которые нужно опросить)
Цитировать
Класс B должен быть написан с условием того, что его методы могут быть вызваны из разных потоков одновременно!
если использовать твою идею - то думаю никаких проблем не должно возникнуть....  (это в моей идее нереально по моему сделать.. т.е. работать не будет)
а если брать твою идею - то можно создавать 3 разных потока, которые принимают входные параметры как на твоем примере:
1. первый поток - будет вечно зациклен на методе exec() ... в нем постоянно будут опрашиваться все нужные узлы
2. второй поток - запускается если вдруг ПРИНУДИТЕЛЬНО нужно опросить какой-то узел (или группу узлов) извне т.е.
    - если нужно быстрее получить с узла данныене (не ждать очереди его опроса по методу polling ... )
    - если у какого-то устройства в конфиге нет флага "автоматический опрос" (т.е. оно не опрашивается в потоке polling - НО оно есть! Улыбающийся )
  и по завершении опроса этих узлов (узла) - поток должен автоматически завершится
3. третий поток - запускается если вдруг ПРИНУДИТЕЛЬНО нужно отправить данные в какой то узел (изменить его состояние) 
и по завершении отправки данных и получения положительной квитанции от у-ва  - поток должен автоматически завершится

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

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

Цитировать
Я не очень понял что должно происходить с флагом manual
ну например:
если какой то внешний класс по какому-то своему алгоритму захочет из класса А получить какие-то готовые данные от узлов то :
 - если узел не имеет в конфиге флага "автоматический опрос" (или еще по какой нить причине)- то внешний класс из класса А вызовет метод с флагом manual (или как нибудь так) - чтобы поток ThreadRead принудительно опросил этот узел ... а потом сам внешний класс просто возмет готовые данные соответствующие этому узлу.... и не беда, что вдруг могут они не обновиться за этот раз.. т.к. в следующие разы они точно обновятся т.к. отработал поток ThreadRead
- если узел ИМЕЕТ в конфиге флаг "автоматический опрос" - то внешний класс читает готовые данные соответствующие узлу прямо из класса А (т.е. не создается поток ThreadRead)

хотя тут у меня еще пока архитектура сумбурная вырисовывается.. но пока что так Улыбающийся

Цитировать
и что требуется от pooling'a (необходимо его запихнуть в отдельную нить или он может вызываться из главной нити по таймеру?).
требуется "вечно" - пока не прервут или не приостановят - опрашивать все узлы по очереди, имеющие в своем конфиге влаг "автоматический опрос"
должен создаваться в отдельную нить.. и опрос вести по таймеру .. я так думаю .. т.к. иначе не будут сигналы работать.. а они в будующем думаю понадобятся
Записан

ArchLinux x86_64 / Win10 64 bit
kuzulis
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2812


Просмотр профиля
« Ответ #32 : Июнь 07, 2009, 17:03 »

Цитировать
Я так понял, что ты хочешь примерно такого (псевдокод!):
дадада.. только еще сюда добавить помимо ThreadRead еще:
1. ThreadWrite
2. ThreaPolling

Улыбающийся
Записан

ArchLinux x86_64 / Win10 64 bit
BRE
Гость
« Ответ #33 : Июнь 07, 2009, 21:58 »

Почитал я еще раз и возникли вопросы:
1. В каждый конкретный момент времени может выполнятся только одна опереция чтения/записи с/на одно устройство?
2. Интерфейсный класс A представляет своим клиента метод чтения/записи. Например, при чтения с одного устройства данных, этот метод останавливается до тех пор пока все данные не будут получены? Или этот процесс идет асинхронно?

А то как-то вроде все заточено под синхронную передачу, для чего тогда отдельные потоки? Я понимаю еще постоянный опрос устройств, а вот остальное.... ?
Записан
kuzulis
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2812


Просмотр профиля
« Ответ #34 : Июнь 08, 2009, 07:55 »

Цитировать
1. В каждый конкретный момент времени может выполнятся только одна опереция чтения/записи с/на одно устройство?

если узлы находятся в сети RS-485 (т.е. подключены например к последовательному порту компа, с конвертером USB/RS-485 к примеру) - то в каждый момент времени выполняется одна транзакция. т.е. сначала отсылаются данные узлу.. а потом принимается ответ от узла... и после этого уже идет разбор принятого ответа , и т.д. и т.п. и сохраняется результат в "массивах готовых данных" Улыбающийся .
т.е защищать мьютексами нужно не по отдельности операции чтения/записи - а транзакцию! (запрос/ответ, запрос/подтверждение и т.п. в зависимости от протокола обмена)

Цитировать
2. Интерфейсный класс A представляет своим клиента метод чтения/записи. Например, при чтения с одного устройства данных, этот метод останавливается до тех пор пока все данные не будут получены? Или этот процесс идет асинхронно?

1. ну, класс А - должен представлять собой самостоятельный объект, который занимается опросом удаленных узлов , сохранения полученных от узлов данных + статусов узлов (т.е например о том что узел недоступен и т.п.)
также класс А для своих "клиентов" просто предоставляет уже готовые данные которые он собрал от узлов.. т.е клиенты из класса А просто запрашивают необходимые им данные...

2. класс не останавливается никогда.. операции автматического опроса узлов ведутся классом непрерывно...  класс А предоставляет своим клиентам ТОЛЬКО методы чтения/записи готовых данных!!! Но не сами методы чтения/записи к узлам! Это уже дело потоков и класса В!
Операции асинхронные... т.е ,еще раз повторю, класс А сам по себе опрашивает узлы и данные о них складывает у себя в массивах(классах/структурах) повторяющих (отображающих) структуру узлов... И для клиентов предоставляется просто интерфейс для  доступа к этой структуре узлов с уже готовыми статусами и данными и т.п.)

т.е класс А будет предоставлять для клиентов иерархическую структуру данных типа:
/
|->канал1 (с параметрами канала)
|        |->узел1 (с параметрами узла)
|        |       |->Данные №1
|        |       |->Данные №2
|        |       |->Данные №N
|        |->узел2 (с параметрами узла)
|                |->Данные №1
|                |->Данные №2
|                |->Данные №N
|

и т.п.

и в конечном итоге чтобы получить  данные №55 от узла №10 в канале №133 этот клиент просто вызовет метод:

А::m_read(Id канала, Id узла, Id Данных, data) = (10, 133, 55)-> и класс А отдаст клиенту готовый кусок содержимого этой структуры (карты сети или как там ее назвать Улыбающийся )

а если нужно клиенту изменить канале №15 узле №11 данные с №19 то вызовет:
A::m_write (Id канала, Id узла, Id Данных, data) = (15, 11, 19, данные)  и все.. а уже сам класс А создаст поток и использует методы класса В для записи данных в узел..  А запущенный постоянно поток polling потом по-любому обновит структуру отображения (т.е. все-равно в конечном итоге опросит узел в котором данные изменились уже)

Вот так как то нужно бы Улыбающийся

Цитировать
А то как-то вроде все заточено под синхронную передачу, для чего тогда отдельные потоки? Я понимаю еще постоянный опрос устройств, а вот остальное.... ?
остальное  - это дополнительный поток для записи данных в узел - нужен тоже! т.к. иначе без потока будет подтормаживать интерфейс.. т.к. транзакции имеют такой параметр - как время ожидания ответа от узла (таймаут) т.е если узел вдруг станет недоступен - а таймаут стоит = 5 сек - то .. сами понимаете Улыбающийся
дополнительный поток - для чтения - это как бы на всякий случай чтобы была такая возможность - принудительно опросить узел...

« Последнее редактирование: Июнь 08, 2009, 08:01 от kuzulis » Записан

ArchLinux x86_64 / Win10 64 bit
BRE
Гость
« Ответ #35 : Июнь 08, 2009, 08:41 »

Цитировать
А то как-то вроде все заточено под синхронную передачу, для чего тогда отдельные потоки? Я понимаю еще постоянный опрос устройств, а вот остальное.... ?
остальное  - это дополнительный поток для записи данных в узел - нужен тоже! т.к. иначе без потока будет подтормаживать интерфейс.. т.к. транзакции имеют такой параметр - как время ожидания ответа от узла (таймаут) т.е если узел вдруг станет недоступен - а таймаут стоит = 5 сек - то .. сами понимаете Улыбающийся
дополнительный поток - для чтения - это как бы на всякий случай чтобы была такая возможность - принудительно опросить узел...
Давай посмотрим со стороны клиента.
Есть алгоритм который должен сравнить данные двух узлов:
Код
C++ (Qt)
void func()
{
   Data data1;
   Data data2;
   m_A->readData( 1, 15, 47, data1 );
   m_A->readData( 2, 12, 44, data2 );
   if( data1 != data2 )
       выводим сообщение
}
 
Что будет происходить: первый вызов readData запустит отдельную нить на чтение, основной поток при этом должен быть приостановлен, до тех пор пока данные не будут прочитаны. Потом тоже будет со вторым readData.
Какой смысл запускать эти нити, если основной поток на это время все равно нужно останавливаться (с подтормаживанием GUI)?
Или делать обмен полностью асинхронным, или смысла в нитях для чтения/записи я не пойму.  Непонимающий
Записан
ритт
Гость
« Ответ #36 : Июнь 08, 2009, 09:59 »

я так понимаю, у kuzulis'а предполагается, что на момент readData( 1, 15, 47, &data1 ) уже будут прочитаны данные как минимум до 1, 15, 48 Улыбающийся
это, конечно, идеализированный вариант. сомневаюсь, что в реальности он будет бессбойно работать xD

а ведь насколько было бы удобнее сделать действительно асинхронную работу, а потом добавить вэйтер, если требуется синхронный вызов Улыбающийся
Записан
BRE
Гость
« Ответ #37 : Июнь 08, 2009, 10:28 »

я так понимаю, у kuzulis'а предполагается, что на момент readData( 1, 15, 47, &data1 ) уже будут прочитаны данные как минимум до 1, 15, 48 Улыбающийся
это, конечно, идеализированный вариант. сомневаюсь, что в реальности он будет бессбойно работать xD
По описание вроде бы так, но для чего использовать дополнительный поток для получения готовых данных для меня осталось загадкой.  Подмигивающий

а ведь насколько было бы удобнее сделать действительно асинхронную работу, а потом добавить вэйтер, если требуется синхронный вызов Улыбающийся
+мульон  Улыбающийся

IMHO, нужно все еще раз хорошо продумать.
Записан
kuzulis
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2812


Просмотр профиля
« Ответ #38 : Июнь 08, 2009, 10:53 »

Цитировать
Что будет происходить: первый вызов readData запустит отдельную нить на чтение, основной поток при этом должен быть приостановлен, до тех пор пока данные не будут прочитаны. Потом тоже будет со вторым readData.
Какой смысл запускать эти нити, если основной поток на это время все равно нужно останавливаться (с подтормаживанием GUI)?
Или делать обмен полностью асинхронным, или смысла в нитях для чтения/записи я не пойму.  Непонимающий

ненене.. m_A->readData - не будет запускать поток... он тока прочитает готовые уже данные  (это если он был вызван с флагом manual=FALSE)
если же он вызывается с флагом manual=TRUE - то приостонавливается поток polling Улыбающийся (или какой там сейчай в данный момент работал поток)

Цитировать
я так понимаю, у kuzulis'а предполагается, что на момент readData( 1, 15, 47, &data1 ) уже будут прочитаны данные как минимум до 1, 15, 48 Улыбающийся

данные потоком polling будут прочитаны из ВСЕХ узлов! т.е все данные и з ВСЕХ узлов! (ну, которые автоматически нужно опрашивать в конфиге) Улыбающийся  и метод m_A->readData - по любому прочитает какие либо данные .. т.е всЁ будет асинхронно происходить!

Цитировать
это, конечно, идеализированный вариант. сомневаюсь, что в реальности он будет бессбойно работать xD
почему? Улыбающийся

Цитировать
а ведь насколько было бы удобнее сделать действительно асинхронную работу, а потом добавить вэйтер, если требуется синхронный вызов Улыбающийся
ну а сейчас она и есть асинхронная!
« Последнее редактирование: Июнь 08, 2009, 11:32 от kuzulis » Записан

ArchLinux x86_64 / Win10 64 bit
kuzulis
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2812


Просмотр профиля
« Ответ #39 : Июнь 08, 2009, 11:06 »

Цитировать
По описание вроде бы так, но для чего использовать дополнительный поток для получения готовых данных для меня осталось загадкой.  Подмигивающий
дополнительный поток - для ПРИНУДИТЕЛЬНОГО ЧТЕНИЯ УЗЛА!!! т.е выдать команду классу А на ПРИНУДИТЕЛЬНОЕ ЧТЕНИЕ узла!!!

т.е :
Код:
A::m_A->readData(111,12,1, manual=true, &adata) {
 /*
если флаг=true - то значит нужно принудительно прочитать данный узел (не знаю для чего - но может понадобится)
запускаем поток и забываем про него - т.к. он сам обновит нам структуры данных от узлов
*/
if (manual) запускаем поток ThreadRead;

/*
просто читаем структуру данных
*/
 data = readReadyData (111,12,1);
}

т.е флаг manual нужен чтобы быстрее обновить данные от узла или чтобы их один раз обновить по запросу или если этот узел в конфиге не опрашивается автоматически (в методе polling он игнорируется если например)

и в дальнейшем просто вызывать можно уже A::m_A->readData(111,12,1, manual=FALSE, &adata)  !!!! т.е мы уже знаем что перед этим уже была команда на обновление ! Улыбающийся
Записан

ArchLinux x86_64 / Win10 64 bit
BRE
Гость
« Ответ #40 : Июнь 08, 2009, 11:07 »

данные потоком polling будут прочитаны из ВСЕХ узлов! т.е все данные и з ВСЕХ узлов! Улыбающийся  и метод m_A->readData - по любому прочитает какие либо данные .. т.е всЁ будет асинхронно происходить!
Вот смотри, создали объект класс А, он запустил ThreadPool, в которой начали опрашиваться все узлы. Он успел опросить только 3 узла, а пользователь нажал кнопку и затребовал данные с 45 узла, ему просто вернуться пустые данные (с флагом что они не валидные)?

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

И все равно, если в один момент времени может происходить только одна транзакция, я не вижу смысла в отдельных потоках чтения/записи.  Подмигивающий  Смеющийся
Записан
BRE
Гость
« Ответ #41 : Июнь 08, 2009, 11:10 »

и в дальнейшем просто вызывать можно уже A::m_A->readData(111,12,1, manual=FALSE, &adata)  !!!! т.е мы уже знаем что перед этим уже была команда на обновление ! Улыбающийся
А через какое время нужно будет вызвать второй раз readData, как можно быть уверенным, что именно сейчас данные уже получены (нить отработала)?  Улыбающийся
Записан
kuzulis
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2812


Просмотр профиля
« Ответ #42 : Июнь 08, 2009, 11:15 »

Цитировать
Вот смотри, создали объект класс А, он запустил ThreadPool, в которой начали опрашиваться все узлы. Он успел опросить только 3 узла, а пользователь нажал кнопку и затребовал данные с 45 узла, ему просто вернуться пустые данные (с флагом что они не валидные)?
дадада.. именно!  т.е у каждого узла помимо данных анализируется еще туева хуча параметров.. таких как статусы! типа :
1. Данные еще не готовы
2. Данные недостоверны
3. и т.п. и. т.д..

Улыбающийся
но статус "Данные еще не готовы" выставится еще только с самого начала.. но после того как узел хотя-бы раз прочитался - этот флаг(статус) снимется Улыбающийся ... т.е данные обновляются всякий раз когда в polling происходит чтение этого узла.. и не беда , если метод m_A->readData прочитает старые данные.. т.к. в следующий раз он может прочитать и новые Улыбающийся

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

а вот тут я потом предполагал сделать эммитинье сигналов самим классом А если данные прочитанные в текущий момент например потоком polling отличаются от данных прочитанных им ранее на предыдущем шаге.. и даже думаю ввести параметр типа : "зона нечувствительности", чтобы часто сигнал не эммитился.. и всё ! Улыбающийся
Записан

ArchLinux x86_64 / Win10 64 bit
kuzulis
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2812


Просмотр профиля
« Ответ #43 : Июнь 08, 2009, 11:19 »

Цитировать
А через какое время нужно будет вызвать второй раз readData, как можно быть уверенным, что именно сейчас данные уже получены (нить отработала)?  Улыбающийся

а тут выход можно сделать с помошью эммитинья сигналов если данные поменялись!

т.е поток polling эмитит эти сигналы например ВСЕГДА (если данные поменялись)!
и поток ThreadRead эмиттит если данные поменялись (если этот поток был запущен)

т.е можно сделать сразу двумя способами:
1. или ловить сигналы от класса А
2. или просто читать готовые данные

или и то и то в комбинировании
Записан

ArchLinux x86_64 / Win10 64 bit
ритт
Гость
« Ответ #44 : Июнь 08, 2009, 11:35 »

а вот на это:
И все равно, если в один момент времени может происходить только одна транзакция, я не вижу смысла в отдельных потоках чтения/записи.  Подмигивающий  Смеющийся
та и не ответил. получается, что запускаем, скажем, пять потоков; один читает, а остальные в это время ждут; затем второй читает, а первый, третий-пятый ждут. ляпота...

и зачем вообще постоянно сигналить о том, что данные прочитались/обновились? ведь это никого не интересует. в лучшем случае может быть интересным сигнал о том, что запрошенные данные готовы. а остальные?
Записан
Страниц: 1 2 [3] 4   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.243 секунд. Запросов: 23.