Jak to dobrze rozwiązać?
Rozumiem że poprzez:
moveToThread(this);
Slot w wątku będzie wykonany przez wątek lecz muszę odpalić:
void Worker::run(){
exec();
}
Jeśli potrzebuję coś w wątku coś ciągle robić, np. generować dane, funkcji:
exec();
nie mogę wykonać, ponieważ uniemożliwi mi to "tworzenie" nowych danych.
Istnieje u mnie taki jeden wątek który uruchamia niskopoziomową bibliotekę która generuje dane.
void QGen::callback(unsigned char * buf, int len){
compute(mData, buf, len);
emit dataChanged(mData);
}
static void gen_callback(unsigned char * buf, uint32_t len, void * ctx){
((QGen*)ctx)->callback(buf, (int)len);
}
void QGen::run()
{
gen_read_async(dev, gen_callback, this/* ctx */, 0, 512);
}
Więc utworzenie:
moveToThread(this);
Wymusi ode mnie, aby sygnały kierowane do wątku QGen, były bezpośrednie "Qt::DirectConnection".
Ale w tym wypadku jest sens przechodzenia?
moveToThread(this);
Doskonale zdaję sobię sprawę, że przy obecnym rozwiązaniu, sloty wykonywane są przez wątki które te sloty wywołały, dlatego zastosowałem mutex'y czy semafory, aby nie było kolizji z wątkiem-run.
Kolejne wątki odbierają dane, przetwarzają i wysyłają dalej.
Znów:
moveToThread(this);
Spowoduje to, że sloty będą musiały mieć "Qt::DirectConnection", aby przez "run()" przetwarzać dane i emitować je dalej.
Mogę także w run wrzucić exec a w slocie przetwarzać dane i emitować dalej:
void Worker::slot(QVector<double> data){ // juz nie moze byc referencji, tylko przekopiowanie danych
MutexLocker ml(&mDataMutex); // jest niekonieczne ponieważ funkcja "slot" wykonywana jest przez wątek "Worker"
compute(mData, data);
emit nextSignal(mData);
}
// wyglad run:
void Worker::run(){
exec();
}
Oczywiście muszę sobie poradzić z problemem:
QObject::connect: Cannot queue arguments of type 'QVector<double>'
(Make sure 'QVector<double>' is registered using qRegisterMetaType().)
Trochę zawiłe i kilka możliwości do przetestowania.
Jak to najlepiej zrobić?