views:

1012

answers:

3

I have a main thread that invokes a child thread function at different times but I am not sure whether that is right way of doing it in Qt.What is wrong with the below code and looking for better alternative

There is a main thread running infinitly when ever main thread releases the lock child does a piece of work.

#include <QtCore/QCoreApplication>
#include <QSemaphore>
#include <QThread> 
QSemaphore sem(0);
class Background : public QThread 
{
protected:
void run() 
{ 
for(;;)
{ 
   sem.acquire(1); 
   qDebug("Child function ran");
} 
} 
};

int main(int argc, char *argv[])  
{   
QCoreApplication a(argc, argv);   
Background child; 
child.start();
qDebug("Main running"); 
qDebug("release a lock");
sem.release(1);
qDebug("Do somework in main");   
//call child
sem.release(1);
sem.release(1);
return a.exec();  
}
A: 

It seems that you might want to use a signal for that, to fit in with the normal Qt style. Check out this question; the accepted answer there seems to match your question too.

MSalters
+3  A: 

Actually your current solution to the problem is quite a nice hack.

If you prefer to do it in a "cleaner" fashion, you should start an event loop in your worker thread. Then the worker thread will be able to receive signals from the main thread. You could call a function in the child thread (using signal/slot mechanism) from the main thread to trigger operation.

See here for more details: http://doc.trolltech.com/4.2/threads.html#per-thread-event-loop

(Hint: The key idea is that you create the receiving object in the worker thread; then its slots will be processed in that thread; or you could use MoveToThread() function)

ypnos
Is it possible to use the pthread in place of child thread
yesraaj
QT does not support pthread in that way. It would ignore the second thread. What is the advantage of pthread compared to QThread?
ypnos
QThread cannot be used since those parts are already built using pThread
yesraaj
As QThread is built on phtread (at least under Unix), you may be able to wrap your existing pthreads into QThreads, it is still possible to access the pthread functions. Search for qthread pthread in Google, people have done it before.
ypnos
ok thanks........
yesraaj
Do u have a Piece of code .I am new to Qt finding difficult to do it
yesraaj
sorry, didn't do it myself yet
ypnos
+2  A: 

Edit: rework of entire post to cover basics as well.

Background.h:

#ifndef BACKGROUND_H
#define BACKGROUND_H

#include <QThread>
#include <QObject>

class Background : public QThread 
{
Q_OBJECT
public:
   Background(QObject* parent = 0):QThread(parent){}
protected:
   void run()
   {
      qDebug(qPrintable(QString("Child function ran in thread: %1").arg(QThread::currentThreadId())));
   }
};

class BackgroundConcurrent : public QObject
{
Q_OBJECT
public:
   BackgroundConcurrent(QObject* parent = 0):QObject(parent){}
public slots:
   void doWork() const
   {
      qDebug(qPrintable(QString("Concurrent child function ran in thread: %1").arg(QThread::currentThreadId())));
   }
};

class BackgroundTrigger : public QObject
{
Q_OBJECT
public:
   BackgroundTrigger(QObject* parent = 0):QObject(parent){}
   ~BackgroundTrigger()
   {
      foreach(QObject* child, children())
      {
         QThread* childThread = qobject_cast<QThread*>(child);
         if (childThread)
            childThread->wait();
      }
   }
public slots:
   void triggerWorker()
   {
      Background* child = new Background(this);
      child->start();
   }
};

#endif // BACKGROUND_H

main.cpp:

#include "Background.h"

#include <QCoreApplication>
#include <QtConcurrentRun>

int main(int argc, char *argv[])  
{   
QCoreApplication a(argc, argv);   

// Using QThread
BackgroundTrigger childTrigger;
qDebug(qPrintable(QString("Main function ran in thread: %1").arg(QThread::currentThreadId())));

// Call child
childTrigger.triggerWorker();
childTrigger.triggerWorker();

// Using QtConcurrent
BackgroundConcurrent cchild;
QFuture<void> future1 = QtConcurrent::run(&cchild, &BackgroundConcurrent::doWork);
QFuture<void> future2 = QtConcurrent::run(&cchild, &BackgroundConcurrent::doWork);

return 0;
}

Sample output:

Main function ran in thread: 1087038064
Child function ran in thread: 1091267472
Child function ran in thread: 1093417872
Concurrent child function ran in thread: 1095519120
Concurrent child function ran in thread: 1097644944

Be sure you run moc on your header files, qmake and cmake both support creating your makefiles.

Here is the CMakeLists.txt file I used to build the code:

cmake_minimum_required(VERSION 2.6)

#Project name
project(TEST)

#Use Qt4
find_package(Qt4)

if(QT4_FOUND)
set(QT_USE_QTOPENGL TRUE)
include(${QT_USE_FILE})

set(LIBS
    ${QT_LIBRARIES}
    )

#Source files (*.cpp, *.o)
set(TEST_SRCS main.cpp)

#Header files (*.h[pp])
set(TEST_HDRS Background.h)

#Qt macros to handle uic, moc, etc...
QT4_WRAP_CPP(TEST_MOC ${TEST_HDRS} OPTIONS -nw)

set(TEST_ALLSRC ${TEST_SRCS} ${TEST_MOC})

#Create main
add_executable(test ${TEST_ALLSRC})
target_link_libraries(test ${LIBS})

endif(QT4_FOUND)
Adam W
Wanted to test it, but does not link. Are you sure doWork() is started in the other thread?
ypnos
Yes, it will. I did not test that code, but that is the general idea, if you tell me the link error, I might be able to fix it before I get to my work machine.Again, if all you want to do is run a function in another thread, please look at QtConcurrent::run()
Adam W
I think gcc is asking to define destructor and constructor for polymorphic class Background , BackgroundTrigger
yesraaj
Ok, I edited it.
Adam W
main.cpp:(.text$_ZN10BackgroundD1Ev[Background::~Background()]+0xb): undefined reference to `vtable for Background'main.cpp:(.text$_ZN17BackgroundTriggerD1Ev[BackgroundTrigger::~BackgroundTrigger()]+0xb): undefined reference to `vtable for BackgroundTrigger'main.cpp:(.text$_ZN17BackgroundTrigger13triggerWorkerEv[BackgroundTrigger::triggerWorker(),BackgroundTrigger::workSignal()'main.cpp:(.text$_ZN17BackgroundTriggerC1Ev[BackgroundTrigger::BackgroundTrigger()]+0x20): undefined reference to `vtable for BackgroundTrigger'
yesraaj
Ok, I did a huge rework to cover everything. It probably should have been another answer, but I wanted to keep it simple. Please look over your build procedures, you can't just run the .cpp through g++ and link to Qt.
Adam W
Actually I have tested your code as said in last comment still getting the linker error,I am accepting to appreciate your effort.I will test in future and update the answer
yesraaj
The code compiles and runs fine here. Clean directory, "qmake-qt4 -project; qmake-qt4; make".A bounty well earned, Adam!
ypnos
Thanks all, I hope you get this to compile yesraaj.
Adam W