PDA

View Full Version : Emitting signals between main GUI thread and non-QThread thread



jansenmd
21st February 2011, 19:34
I'm trying to figure out how to emit Signals from a thread to be captured by Slots in the main GUI thread. The thread is used to read serial port data. The thread is NOT a QThread. It's a generic Win32 thread created via CreateThread().

The Win32 thread is passed a pointer to a Serial class object. This object has a ThreadProc member function in which the thread runs. The Serial class inherits from QObject and declares the Signal member function.

The connection between the Signal and Slot is made in the main GUI window constructor. If I leave the connection type out so it picks Automatic, I can emit the Signal from the Serial object as long as it is called from the main GUI thread (as when I'm configuring the Serial object before starting the thread). However, any calls to emit the Signal from within the thread do not arrive at the Slot. If I change the connection type to QueuedConnection, none of the Signals make it to the Slot. Not even the ones called from within the main GUI thread.

What is this Qt newbie doing wrong? Using Qt 4.7.


Here are some code snippets:

#include <QObject>
class Serial : public QObject
{
Q_OBJECT

public:
Serial();
virtual ~Serial();

void Run();

protected:
static DWORD WINAPI ThreadProc (LPVOID lpArg); // 'lpArg' is a pointer to an instance of this class
DWORD ThreadProc (void); // run-loop of the thread, called by the above static function.

signals:
void SerialEventSignal(unsigned int event);
};

void Serial::Run()
{
emit SerialEventSignal(1); // works with Automatic connection, fails with QueuedConnection
DWORD dwThreadId = 0;
m_hThread = ::CreateThread(0,0,ThreadProc,LPVOID(this),0,&dwThreadId);
}

DWORD WINAPI Serial::ThreadProc(LPVOID lpArg)
{
Serial* pThis = reinterpret_cast<Serial*>(lpArg);
return pThis->ThreadProc();
}

DWORD Serial::ThreadProc (void)
{
emit SerialEventSignal(2); // Always fails
while (true)
{
// do stuff
}
}

wysota
21st February 2011, 21:33
Show us how your slot is declared and used.

jansenmd
21st February 2011, 21:48
I'm at a new location now and don't have the code in front of me, but it's roughly this.

class MainWindow : public [main GUI window inheritance stuff]
{
Serial m_SerialPort;

...

private slots:
void SerialEventSlot(unsigned int event);
};

MainWindow::MainWindow()
{
...

connect(&m_SerialPort, SIGNAL(SerialEventSignal(unsigned int)), this, SLOT(SerialEventSlot(unsigned int))); // this call seems to fail if I try to use 'Qt::QueuedConnection'
}

void MainWindow::on_buttonClicked()
{
m_SerialPort.Run(); // This causes the receiver thread to be created.
}

void MainWindow::SerialEventSlot(unsigned int event)
{
std::cout << "Detected a Serial Event: " << event << std::endl;
}

wysota
22nd February 2011, 00:03
Please dump the QThread::currentThreadId() value (it's a static method) before creating the worker thread and then before emitting the signal. Are they the same or different?

jansenmd
22nd February 2011, 00:48
I will post the results of doing the dump tomorrow when I have access to my system again.

EDIT: In the mean time, where should I look for information on how threading works in Qt? The official documentation is rather lacking. I still don't understand how run() and exec() are supposed to be used. I've even read some blogs about how most people are apparently "doing it wrong" when it comes to threading because that's what the documentation says to do (overriding run()).

What I'm looking for is a thread that can block forever on a call to WaitForSingleObject() (Win32 API) and still emit Signals when not blocked. I don't care if the thread used is a QThread, a native Win32 thread, or something else. But everything I understand from the doucmentation and doing searches is you can't block on something like WaitForSingleObject() and still emit Signals (because exec() isn't being executed?). Is this true? If so, what's the work-around for blocked threads and Signals/Slots usage?

Thanks.

wysota
22nd February 2011, 21:21
If a thread is blocked, it's not scheduled by the operating system, so it can't do anything, be it emitting a signal or adding two ints together. Your design is just plainly wrong for the current computer architectures. Maybe try describing what is the ultimate effect you want to achieve and we'll help you find a good design for it.