2013-03-01 10 views
10

Używam biblioteki QtSerialPort do komunikowania się z wirtualnym portem COM przez USB. Port COM zwraca dane i działa prawidłowo podczas testowania z przykładowymi projektami podanymi w QtSerialPort, ale nie działa, gdy uruchamiam go jako część mojego projektu.Utworzenie QtSerialPort w niewłaściwym wątku, powodujące zawieszenie się sygnałów/gniazd

Sprawdziłem łańcuch instancji i wątki prowadzące do instancji QtSerialPort i odkryłem coś dziwnego. Wyniki są poniżej.

main() 
    MainWindow (Thread 0xbf8dbe0)  // Thread "A" 
    HardwareManager (Thread 0xbf8dbe0) // Thread "A" 
     QSerialPort (Thread 0xbfb95f0) // Thread "B" !? 

W moim kodzie main() funkcja instancję MainWindow, co z kolei instancję HardwareManager i zapisuje go jako zmienną prywatnego. Kiedy instancja HardwareManager jest instancjonowana, tworzy także instancję QSerialPort, dzięki czemu może poprawnie rozmawiać z portem COM.

Jednak zauważysz, że nad moim QSerialPort znajduje się inny wątek niż obiekt nadrzędny, a także jego obiekt nadrzędny (jest w wątku B, podczas gdy obaj przodkowie są w wątku A). Myślę, że ten inny wątek powoduje awarię moich Sygnałów/Slotów. Jeśli I dumpObjectInfo, wyświetla on mój Sygnał/Gniazdo jako skonfigurowany, ale zdarzenia nigdy się nie uruchamiają.

this->serial = new QSerialPort(); 
connect(this->serial, SIGNAL(readyRead()), this, SLOT(readSerialData()); 

Powyżej znajduje się kod, którego używam do utworzenia nowego portu szeregowego i podłączenia go do właściwego gniazda. Rzeczywista konfiguracja bitów, parzystości i danych/bitów stopu odbywa się osobno (i działa poprawnie, jak testowano w przykładowej aplikacji dostarczonej przez QtSerialPort).

Czy ktoś ma wgląd w to, dlaczego ten konkretny obiekt (instancja QSerialPort) jest tworzony w innym wątku? Próbowałem "moveToThread", aby zmienić powiązanie wątku, ale nic nie działa.

Zrobiłem też post on the Qt Project Forums, ale nie miałem jeszcze żadnych użytecznych odpowiedzi.

Edit: Poniżej znajduje się odpowiedni kod w łańcuchu połączenia:

// main() 
QApplication a(argc, argv) 
MainWindow window = new MainWindow(); // [1] 
MainWindow.show(); 
return a.exec(); 

// MainWindow::MainWindow() [1] 
this->toolController = new QtToolController(this); 
HardwareManager *manager = new HardwareManager(this->toolController); // [2] 

// HardwareManager::HardwareManager() [2] 
this->serial = new QSerialPort(); 
connect(this->serial, SIGNAL(readyRead()), this, SLOT(readSerialData())); 

Kiedy QSerialPort jest gotowy do odczytu z (ma danych do dostarczenia), pożary sygnał readyRead (przynajmniej tak powinno być). Ten sygnał jest uruchamiany poprawnie w projektach Qt przykład, ale nigdy nie dostaję sygnału w mojej aplikacji. Uważam, że powodem, dla którego nie otrzymuję sygnału, są problemy z wątkami.

+1

Nie wiem, jak działa QT, więc tylko dzikie domysły: czy tworzysz 'QSerialPort' w odpowiedzi na jakieś wydarzenie? Czy istnieje jakakolwiek szansa, którą program obsługi zdarzenia wywołał w kontekście innego wątku? –

+0

Nie. Instancja QSerialPort znajduje się w instancji HardwareManager, która znajduje się w instancji MainWindow, która jest wywoływana w metodzie main(). W tym momencie nie ma sygnałów/gniazd/wywołań zwrotnych. –

+0

Uważam, że nie powinieneś zawracać sobie głowy innym wątkiem, powinieneś zawracać sobie głowę niepracującymi sygnałami/gniazdami. Pokaż nam swoją główną, proszę. I podaj trochę informacji o tym, kiedy automat powinien wystrzelić – ixSci

Odpowiedz

1

W duchu utrzymywania odpowiedzi dostępnych dla każdego, kto napotkał ten problem, problem był związany z wersjami Release/Debug. Biblioteka QtSerialPort została zbudowana TYLKO dla mojego środowiska Release i z jakiegoś powodu, po uruchomieniu mojej aplikacji w trybie debugowania byłaby linkiem do Release QtSerialPort, a konteksty wątków zostałyby zgubione.

Aby to naprawić, upewniłem się, że zbudowałem odpowiednią wersję biblioteki, a następnie zapewniono, że połączyłem ją z odpowiednią wersją dla mojego środowiska.

2

Można użyć QueuedConnection do przechwytywania sygnałów z innego wątku.

connect(this->serial, SIGNAL(readyRead()), 
    this, SLOT(readSerialData()), Qt::QueuedConnection); 

W ten sposób gniazdo powinno zostać wykonane w kontekście wątku głównego, po powrocie kontrolki do pętli zdarzeń.

Wydaje się także, że this post sugeruje, że nie powinieneś ustawiać rodzica dla QtSerialPort (prawdopodobnie dlatego, że moveToThread nie działa z QObjects z rodzicami).

+0

Dodanie parametru Qt :: QueuedConnection nie powinno być konieczne, ponieważ domyślny Qt :: AutoConnection (używam Qt 5, nie jestem pewien o Qt 4) również poprawnie obsługuje połączenia między różnymi wątkami. – FourtyTwo

Powiązane problemy