Russian Qt Forum

Qt => Многопоточное программирование, процессы => Тема начата: thechicho от Ноябрь 06, 2011, 11:17



Название: Разграничение передачи сигнала в несколько потоков
Отправлено: thechicho от Ноябрь 06, 2011, 11:17
Из главного потока необходимо посылать сигнал в дочерние.

потоки создаются:
Код
C++ (Qt)
for (int i = 0; i < N; i++ {
NewThread *thread = new NewThread(this);
connect(this, SIGNAL(StringSignal(QString &)), thread, SLOT(StringSlot(QString &)));
}

сигнал посылается:
Код
C++ (Qt)
void anySlot()
{
   QString test= "test";
   emit StringSignal(test);
}

таким образом, сигнал пойдет во все потоки?
а как разграничить можно? чтобы сигнал посылался в конкретный поток. типа
Код
C++ (Qt)
emit StringSignal(test, threadN);


Название: Re: Разграничение передачи сигнала в несколько потоков
Отправлено: LisandreL от Ноябрь 06, 2011, 11:36
Присоединять сигнал только к этому слоту (можно через сигнал маппер, получится примерно то, что вы описали).
Ну или QMetaObject::invoke вместо эмита.


Название: Re: Разграничение передачи сигнала в несколько потоков
Отправлено: Ubuntu_linux от Ноябрь 06, 2011, 20:15
Кстати, сигнал можно конектить к сигналу!


Название: Re: Разграничение передачи сигнала в несколько потоков
Отправлено: thechicho от Ноябрь 07, 2011, 11:22
// Присоединять сигнал только к этому слоту (можно через сигнал маппер, получится примерно то, что вы описали).
сорри, не очень понял. вернее совсем не понял. если я создам 10 потоков, для каждого нужно connect и слоты? так не вариант...
поясни, плиз, как это реализуется. или хотя б как сигнал маппер в документации можно найти (как он на английском звучит).

// Кстати, сигнал можно конектить к сигналу!
я знал, я знал!
если серьезно, не представляю как это может помочь.


Название: Re: Разграничение передачи сигнала в несколько потоков
Отправлено: Waryable от Ноябрь 07, 2011, 12:37
В сигнале посылайте указатель на поток. В слоте проверяйте указатель и решайте обрабатывать или нет.


Название: Re: Разграничение передачи сигнала в несколько потоков
Отправлено: thechicho от Ноябрь 07, 2011, 13:49
сенкс за ваши ответы!
решил сделать по-другому.
передал указатели на QLineEdit  в поток, и прямо оттуда читаю введеный текст, при получении сигнала из главного потока, связанного с указателями QLineEdit.

.h
Код
C++ (Qt)
QList<QLineEdit*> lineEditList;

.cpp
Код
C++ (Qt)
for (int i = 0; i < N; i++ {
QLineEdit *lineEditDialog = new QLineEdit(dialog);
lineEditList<< lineEditDialog;
}
 
for (int i = 0; i < N; i++ {
NewThread *thread = new NewThread(this);
connect(lineEditList[i], SIGNAL(returnPressed()), thread, SLOT(StringSlot()));
}

работает так, как я и хотел :)


Название: Re: Разграничение передачи сигнала в несколько потоков
Отправлено: JamS007 от Январь 03, 2012, 23:52
Привет!
Была аналогичная задача.
Нужно было посылать уведомление в один или несколько потоков из общего пула. Долго копал документацию по этому поводу, в конце концов вот к чему пришел:
В доке сказано, что сигналы между потоками преобразуются в ивенты (QEvent) и обрабатываться exec()-циклом внутри потока, в связи с чем было принято решение реализовать собственный механизм отправки сообщений с помощью QEvent:

У меня уведомление было связано с появлением нового клиента, поэтому класс сообщения об этом так и назван, уж простите за семантику :)

Класс сообщения выглядит следующим образом:
Код
C++ (Qt)
class NewClientEvent: public QEvent
{
public:
   static const QEvent::Type ET_NewClientEvent = (QEvent::Type)2000;
   explicit NewClientEvent():
   // ...
};

В классе потока следующим образом переопределена функция event():
Код
C++ (Qt)
bool WorkThread::event(QEvent *event)
{
   if (event && event->type() == NewClientEvent::ET_NewClientEvent){
       // ...
       return true;
   }
   return QThread::event(event);
}

В основном классе создаю потоки таким образом:
Код
C++ (Qt)
mThreadsList = new std::vector<WorkThread*>();
mThreadsList->reserve(idealThreadsCount());
for (int i=0; i<mThreadsList->capacity(); ++i){
   WorkThread *thread = new WorkThread(mRequestsHandler, 0);
   thread->start();
   mThreadsList->push_back(thread);
}

Ну а сообщения посылал так:
Код
C++ (Qt)
QThread *thread = mThreadsPool->nextThread();
if (! thread)
   return;
 
NewClientEvent *event = new NewClientEvent(handle);
QCoreApplication::postEvent(thread, event);

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


Название: Re: Разграничение передачи сигнала в несколько потоков
Отправлено: andrew.k от Январь 04, 2012, 00:06
сенкс за ваши ответы!
решил сделать по-другому.
передал указатели на QLineEdit  в поток, и прямо оттуда читаю введеный текст, при получении сигнала из главного потока, связанного с указателями QLineEdit.

работает так, как я и хотел :)
Жесть. Из других потоков нельзя взаимодействовать с GUI (по-крайней мере так рекомендуется в документации). И если у тебя оно работает, это до поры до времени, а как сломается, устанешь искать баги.
invokeMethod то, что тебе нужно, посылай в нужный поток.


Название: Re: Разграничение передачи сигнала в несколько потоков
Отправлено: thechicho от Январь 06, 2012, 17:18
да я по-другому сделал.
создал слот в потоке и соединил гуишные элементы с этим слотом. гуи посылает сигнал, в этот слот.
вот и все.
правда, все равно 1 элемент скопировал в поток. есть groupbox, в кот. 2 qradiobutton. указатель на 1 qradiobutton копируется в поток. там проверяется на отмечен. чтобы можно было в режиме реального времени условие поменять... в принципе можно и слот сделать в гуи потоке и в потоки передавать bool переменную, а в этом слоте ее менять... но прогу я писал для себя, так что не заморачиваюсь на этот счет. ну упадет при проверке isChecked ()  (во что нео4 верится  :)), ну запущу по новой :D если вдруг будет часто падать, добавлю в слоте изменение условия.
короче мораль - надо делать проще и чтобы работало :D


Название: Re: Разграничение передачи сигнала в несколько потоков
Отправлено: andrew.k от Январь 06, 2012, 17:26
да я по-другому сделал.
создал слот в потоке и соединил гуишные элементы с этим слотом. гуи посылает сигнал, в этот слот.
вот и все.
правда, все равно 1 элемент скопировал в поток. есть groupbox, в кот. 2 qradiobutton. указатель на 1 qradiobutton копируется в поток. там проверяется на отмечен. чтобы можно было в режиме реального времени условие поменять... в принципе можно и слот сделать в гуи потоке и в потоки передавать bool переменную, а в этом слоте ее менять... но прогу я писал для себя, так что не заморачиваюсь на этот счет. ну упадет при проверке isChecked ()  (во что нео4 верится  :)), ну запущу по новой :D если вдруг будет часто падать, добавлю в слоте изменение условия.
короче мораль - надо делать проще и чтобы работало :D
Надо делать грамотно и для себя и для других.


Название: Re: Разграничение передачи сигнала в несколько потоков
Отправлено: thechicho от Январь 06, 2012, 17:40
надо делать, чтобы работало
надо делать, чтобы работало быстро и стабильно

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


Название: Re: Разграничение передачи сигнала в несколько потоков
Отправлено: Akon от Январь 06, 2012, 21:48
2HaySayCheese:
А почему использовали именно события (QEvent); сигнал/слот механизм чем не устроил? Первое сопряжено с синтаксическим оверхедом.


Название: Re: Разграничение передачи сигнала в несколько потоков
Отправлено: andrew.k от Январь 06, 2012, 23:17
надо делать, чтобы работало
Вот поэтому у нас все так. Потому что все "делают, чтобы работало".


Название: Re: Разграничение передачи сигнала в несколько потоков
Отправлено: thechicho от Январь 07, 2012, 01:26
а как у вас? ;)
фишка в том, что я пишу, как умею.
мне проги нужны, а не красивый код.


Название: Re: Разграничение передачи сигнала в несколько потоков
Отправлено: popper от Январь 07, 2012, 11:41
а тестирование программы принято поручать конечным пользователям
и кто-то все написанное с целью "чтобы работало" должен как-то поддерживать


Название: Re: Разграничение передачи сигнала в несколько потоков
Отправлено: thechicho от Январь 07, 2012, 12:00
странные вы какие-то. кодерская болезнь может какая :D
я пишу софт для себя и для своих. поэтому такой подход.
если бы я писал на продажу или работал "на дядю" и писал в команде, разумеется я бы со всей ответственностью подошел к написанию кода, по мере своих знаний.

я уверен на 100500%, что тот, кто другого называет быдлокодером, сам тупит в коде тоже хотяб 10-15%.
анекдот: работают вместе 2 кодера. 1 чота написал, другой мысленно: "да зае этот быдлокодер тупой О_о". 2 чота написал, 1ый: "да зае этот быдлокодер тупой О_о". вот и вся мораль про быдлокодерство.
лан, харе флудить, тема сисек давно раскрыта :)


Название: Re: Разграничение передачи сигнала в несколько потоков
Отправлено: Fregloin от Март 03, 2012, 17:38
какойто неадекват.
а по теме, про передачу евентов в поток то что мне нужно, спасибо!


Название: Re: Разграничение передачи сигнала в несколько потоков
Отправлено: Bepec от Март 03, 2012, 22:26
Без красивых подходов, не видать красивых программ.

А Ичико наш местный тролль ;)


Название: Re: Разграничение передачи сигнала в несколько потоков
Отправлено: Fregloin от Март 12, 2012, 17:05
хотя заметил, что event отсылаемый потоку почему то все равно выполняется в главном потоке...


Название: Re: Разграничение передачи сигнала в несколько потоков
Отправлено: vbi от Март 13, 2012, 17:06
Я как-то делал так:
В конструктор потока передавал ИД (число, например порядковый номер)

а при отправке сигнала в качестве второго параметра передавал бы нужный ИД. А каждый поток в себе проверяет его ли этот ИД или не его. если не его, то возврат, если его - делает свое дело:

Код:
for (int i = 0; i < N; i++ {
NewThread *thread = new NewThread(i,this);
connect(this, SIGNAL(StringSignal(QString &, int)), thread, SLOT(StringSlot(QString &, int)));
}

emit StringSignal("TEST", 9); // только поток с ИД 9 получит сигнал, проверит, что его ИД тоже 9 тогда выполнит какие-то действия. Остальные потоки ничего не будут делать.
Такой механизм, мною написаный, работает прямо сейчас в Варшавском ДЕПО :)


Название: Re: Разграничение передачи сигнала в несколько потоков
Отправлено: thechicho от Апрель 28, 2013, 16:38
vbi, ваш сигнал поступит во все потоки. но код выполнит только поток с ид 9.

Для такой задачи можно, например, создать в .h
private:
    QList<NewThread *> threads;

затем в цикле записать
//threads.clear();
for (int i = 0; i < N; i++ {
    ...
    threads.append(thread);
    ...
}

и можно обращаться на прямую к полям и методам нужного потока
thread.at(9)->anyVariable = "blabla";
thread.at(9)->processingAnything(...);

а вообще работает, да и пофик :)