PDA

View Full Version : multithreading programming in Qt



Sheng
27th October 2008, 13:07
I have a class A, I want to run A::function() in a new thread.
After generate a new thread class MyThread: public QThread, I can override run funtion.
But how can I use the A::function in the run() function? I need to use a lot of variables defined in class A.
If I generate a signal in MyThread to run A::function, is it in another thread? or in the main thread, since after generate the signal, the new thread finishes it's job.
Thanks a lot for your opinion.

defender
27th October 2008, 16:11
I have a class A, I want to run A::function() in a new thread.
After generate a new thread class MyThread: public QThread, I can override run funtion.
But how can I use the A::function in the run() function? I need to use a lot of variables defined in class A.
If I generate a signal in MyThread to run A::function, is it in another thread? or in the main thread, since after generate the signal, the new thread finishes it's job.
Thanks a lot for your opinion.
All code, before you start thread by QThread::start, run in the thread-creator of MyThread object (including constructor etc.). Code, listed in MyThread::run in separate thread (after calling start()). But you still have access to ALL data and methods in MyThread, because all threads share all data and code (don't forgot separate access to shared data by mutexes/semaphores)

PS
Sorry on my English.....

Sheng
27th October 2008, 16:57
All code, before you start thread by QThread::start, run in the thread-creator of MyThread object (including constructor etc.). Code, listed in MyThread::run in separate thread (after calling start()). But you still have access to ALL data and methods in MyThread, because all threads share all data and code (don't forgot separate access to shared data by mutexes/semaphores)

PS
Sorry on my English.....

I understand I can access all data and methods in MyThread, but can I access variables in class A?
Let me explain my question more clearly, In class A, I have function(),
void A::function()
{
}
and a MyThread object
MyThread thread;

If I override MyThread::run(), how can I call A::function? Apparently I can not call it directly and I have to use signal, but I am wondering if I use signal, A::function() will run in main thread instead of a secondary thread.

Sheng
27th October 2008, 17:07
I understand I can access all data and methods in MyThread, but can I access variables in class A?
Let me explain my question more clearly, In class A, I have function(),
void A::function()
{
}
and a MyThread object
MyThread thread;

If I override MyThread::run(), how can I call A::function? Apparently I can not call it directly and I have to use signal, but I am wondering if I use signal, A::function() will run in main thread instead of a secondary thread.

OK, I think I get the answer when I read the detailed information of QThread class.
"With direct connections, the slot gets called immediately when the signal is emitted. The slot is executed in the thread that emitted the signal (which is not necessarily the thread where the receiver object lives).", so the A::function() should be run in a secondary thread.
That's what I want, just add a fifth parameter Qt:: DirectConnection in the connect function defined in class A.

wysota
27th October 2008, 23:29
I understand I can access all data and methods in MyThread, but can I access variables in class A?

It depends. If you ask is it possible to call the method then yes, this is possible - all you need is a pointer to the object and you can call its method as usual. If you ask if it is safe to do it, then the answer depends on what the method does and how the A class is designed. In that case read about reentrancy and thread-safety.

Sheng
28th October 2008, 13:24
It depends. If you ask is it possible to call the method then yes, this is possible - all you need is a pointer to the object and you can call its method as usual. If you ask if it is safe to do it, then the answer depends on what the method does and how the A class is designed. In that case read about reentrancy and thread-safety.

Thanks, you are right. But I think it is dangerous to do that, even when A is singleton class, it might cause infinite recursive call in some case.

defender
28th October 2008, 14:22
Thanks, you are right. But I think it is dangerous to do that, even when A is singleton class, it might cause infinite recursive call in some case.
Let's see.
I have class A. It implement some calculate process:


class A {
public:
A();
void setData(const sometype __d);
void calc();
private:
sometype data;
QMutex data_mutex;
};

void A::setData(const sometype __d) {
if(data_mutex.tryLock()) // error to user;
data=__d;
data_mutex.unlock();
}
void A::calc() {
if(!data_mutex.tryLock()) {
QMessageBox::warning(NULL,"Lock","Data is still locked!");
return;
}
while(1) {
///calculate
}
data_mutex.unlock();
}

Can show to me on an example of this class, what sort of a problem can arise? Also what you understand as infinite recursive calls? You can loss data? Two (or more) threads can go into conditional race?
Please, specify peace of code where you plan to use such classes.

Sheng
28th October 2008, 15:18
Let's see.
I have class A. It implement some calculate process:

class A {
public:
A();
void setData(const sometype __d);
void calc();
private:
sometype data;
QMutex data_mutex;
};

void A::setData(const sometype __d) {
if(data_mutex.tryLock()) // error to user;
data=__d;
data_mutex.unlock();
}
void A::calc() {
if(!data_mutex.tryLock()) {
QMessageBox::warning(NULL,"Lock","Data is still locked!");
return;
}
while(1) {
///calculate
}
data_mutex.unlock();
}

Can show to me on an example of this class, what sort of a problem can arise? Also what you understand as infinite recursive calls? You can loss data? Two (or more) threads can go into conditional race?
Please, specify peace of code where you plan to use such classes.

I mean, in general, this kind of design might cause problems. But if you say whether we can do it or not, we certainly can.
a simple example:

class A
{
public:
A();
~A();
void functionA();
void run();

};

class B
{
public:
B();
~B();
void functionB();
A* a;
};

void A::functionA()
{cout<<"functionA"<<endl;
B* b=new B;
b->functionB();
delete b;
}

void A::run()
{ B* b=new B;
b->functionB();
delete b;
}

A::A()
{
}

A::~A()
{
}


B::B()
{
a=new A;
}

B::~B()
{
}

void B::functionB()
{
cout<<"functionB"<<endl;
A* a=new A;
a->functionA();
delete a;
}

int main()
{
B b;
b.a->run();
}

wysota
28th October 2008, 17:14
Can show to me on an example of this class, what sort of a problem can arise?

If you use a mutex then you are safe when it comes to race conditions. But why are you using tryLock() instead of lock()? Currently you indeed can lose data as the lock may fail if another thread is already in the critical section and your data won't be saved. What is dangerous in the above code is the call to QMessageBox from a worker thread.

defender
29th October 2008, 06:22
If you use a mutex then you are safe when it comes to race conditions. But why are you using tryLock() instead of lock()? Currently you indeed can lose data as the lock may fail if another thread is already in the critical section and your data won't be saved. What is dangerous in the above code is the call to QMessageBox from a worker thread.
If we imaging, what class A is the GUI thread and class MyThread -- is calculate thread, then using lock, instead of tryLock, will block GUI thread. QMessageBox -- is a simple example. We must replace it with an error handler.

wysota
29th October 2008, 08:01
If you lock for long enough for your user to notice it, then yes. But then you should probably change your design. If you lock only to set some value, don't worry about it. I'd suggest changing the design a little. For instance introduce the usage of signals and slots - then you don't have to do any locking at all.