PDA

View Full Version : Threading...?



sekatsim
1st June 2008, 22:01
I'm very new to QT, but I need to write an interface to a DMX lighting controller that I've built, and QT seemed like the easiest way. I'm really enjoying it so far, but I don't quite understand Threads.

Here's what I'd like to do:

The program is normally controlled by the mouse/keyboard, but there is an option to control it with a usb joystick.

When the user clicks the "enable joystick" check box, a joystick thread should be started (I believe this is the most efficient way, but if not, I'd be happy to receive suggestions). This joystick thread should check the status of the joystick every 2ms or so, and when there is a change, it should notify the rest of the program.

I've gotten the joystick thread to start when I click the start checkbox, and it outputs the joystick state to the terminal perfectly, so I know that is working. However, I dont know how to send it back to my Main thread.

I tried calling a main thread function from within the joystick thread, and having that function update the display, but the program crashed with about 60, "QPixmap: It is not safe to use pixmaps outside the GUI thread"s. I think this is because the function is still being run within the joystick thread, and it crashes when it tries to redraw the screen.

What I'd really like is for the joystick to emit a signal on every change of state, just like a widget. And then I'd like to have a series of slots to receive them, but doing that across threads is beyond me.

Any suggestions anyone can give would be most welcome.

Aceman2000
1st June 2008, 22:04
Specify Qt::QueuedConnection as the fifth parameter for connect() (there's Qt::BlockingQueuedConnection also). This will make the emitted signal thread-safe.

sekatsim
1st June 2008, 22:16
So could I add a connect in my main thread with the rest of my GUI connects? Something like...

connect(joystickButton1Press, SIGNAL(pressed()), nameofJoyStickClass, SLOT(joyButton1Pressed()), Qt::QueuedConnection);

?

or would QT::QueuedConnection go where I currently have "nameofJoyStickClass"?

Also, what would the "emit" section within the joystick thread look like? The same as a regular QPushButton, or would it also be threading specific?

sekatsim
2nd June 2008, 00:09
Alright, I put an


emit axischanged(aPos[ev.number]);

in the joystick controller. I set up a connect alongside my other GUI connects like so:


connect(&thread,SIGNAL(axischanged(int)),this,SLOT(joyOpts( int)),Qt::QueuedConnection);

It compiles successfully, and runs. However, when I enable the joystick, it crashes. Debug revealed:


[Thread debugging using libthread_db enabled]
[New Thread 0x40a88950 (LWP 5623)]
Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x40a88950 (LWP 5623)]
0x00007fc3cb47593c in QMetaObject::activate () from /usr/lib/libQtCore.so.4
(gdb)
QThread: Destroyed while thread is still running

In fact, I'm getting a lot of QThread: Destroyed messages. I havent set a destructor though.. it's just supposed to run infinitely.

Any thoughts?

Thank you for your help thus far

don_simmmel
2nd June 2008, 08:32
hi
it seems that you instantiated your thread as a local variable of a method.
What happens is, that when the programm leaves this method, the thread becomes destroyed and sends this message.

-> Place the the instance into the *.h file and initialize it afterwards in the constructor or the method you like.

good luck

sekatsim
2nd June 2008, 12:49
I'm sorry, I don't quite understand. I have


class joystick1Thread : public QThread
{
Q_OBJECT

signals:
void axischanged();

public:
void prepare();

protected:
void run();

};

In my .h file. Are you saying that I should put my "connect" in the .h file as well?

jacek
3rd June 2008, 23:13
In my .h file. Are you saying that I should put my "connect" in the .h file as well?
No, don_simmmel suggested that you should try making your thread a member variable, instead of local one.

steg90
4th June 2008, 15:53
Sounds like a typical usage for the Observer pattern ;)

Regards.
Steve

sekatsim
6th June 2008, 01:40
I've been playing with this when I've gotten time during the week, and still no results.

When you say I should make my thread a member variable, do you mean the declaration of the thread, the actual physical thread itself, or the "connect" command? As far as I could tell according to the QT documentation, I have it set up correctly. If you could tell me what section of my code I should put where, I'd love to try it out.

The thread has its own class, which is declared in the mainwindowimpl.h file, I dont know how much more global I can get than that.

jacek
6th June 2008, 02:19
When you say I should make my thread a member variable, do you mean the declaration of the thread, the actual physical thread itself, or the "connect" command?
None of these things is a variable. "thread" which appears in post #4 is a variable and it's the one don_simmmel had on mind. Where do you declare it?

sekatsim
6th June 2008, 03:47
Okay, now I understand. I didnt even consider that, as I'd copied this as close-to-originally as possible from the Mandelbrot example. "thread" was declared in the "private:" of mainwindowimpl. I moved it into "public:", and the program no longer crashes when I enable the joystick.

However, I still get a "QThread: Destroyed while thread is still running" on enable, and the connect still seems to be failing.

Where *should* I be declaring "thread"?

jacek
8th June 2008, 00:08
Where *should* I be declaring "thread"?
Making it a member variable is a good solution, provided that the object it's member of will exist longer than the thread runs.

When exactly do you get that "Destroyed while thread is still running" message?

sekatsim
10th June 2008, 01:14
Thanks, I got it working. I basically just started over from scratch, using the Mandelbrot example, and then gradually modified it to suit my own purposes.