PDA

View Full Version : GUI thread blocked using QThread.



summer_of_69
15th May 2009, 08:55
Hi All,

I have created one class LogTask to store logs in certain file.
My problem is it's blocking GUI thread when I call Log(QString("")) .

Here is the code.

Can anyone help me with this???:confused:

Thanks in Advance
---



Task.cpp

typedef QList<QEvent*> Pocket;
Pocket mypocket;
Task::Task():QThread() //constructor for task
{
taskmanager::addTask(this); //adding task to the tasklist
stopsignal = false;

}

void Task::run(){
while (!stopsignal)
{
mymutex.lock();
mycondition.wait(&mymutex);

// got a signal..now process
processIncomingEvents();
mymutex.unlock();

}
}

void Task::processIncomingEvents()
{
QEvent* e = mypocket.first();
while (e){
handleEvent(e);
mymutex.lock();
mypocket.remove(e);
mymutex.unlock();
e = mypocket.first();
}
//mypocket.clear();
}





LogTask.h

#define FILE_PATH "d:/Aer2.log"
#define Log(x) LogTask::OutputDebugLog(QString(x+" in %1 in %2 at %3").arg(__FILE__).arg(__FUNCTION__).arg(__LINE__))

class LogTask : public Task
{
public:
LogTask();
~LogTask();

bool Initialize();
bool Finalize();
virtual void handleEvent( QEvent* ev );
static void OutputDebugLog( const QString & );

};

//##################################################


LogTask.cpp

LogTask* currentlogtask=0;

LogTask::LogTask()
{
currentlogtask = this;
}

LogTask::~LogTask()
{
qDebug("Logtask ended");
currentlogtask = 0;
}

bool LogTask::Initialize()
{

/*
file.setName(FILE_NAME);
if (!file.open(IO_WriteOnly | IO_Append))
return -1;
ts.setDevice(&file);*/

return true;
}

bool LogTask::Finalize()
{
//ts.flush();
//ts.close();
//file.close();
return true;
}

void LogTask::OutputDebugLog(const QString &str)
{

if (currentlogtask)
currentlogtask->acceptEvent( new HonCustomEvent(ETLOG, 0, 0, new QString(str)));
}



void LogTask::handleEvent( QEvent* ev )
{
HonCustomEvent* rev = (HonCustomEvent*) ev;
if (rev->eventtype == ETLOG)
{
QString path = FILE_PATH;
QString* str = (QString* )rev->ptr;
QFileInfo fileinfo(path);

if(fileinfo.size() >= 5000000)
{ ///If file is 5MB in size change the file to output everything
QString newpath = QString(FILE_PATH)+"."+"0";
QFileInfo tmpinfo(newpath);
if(tmpinfo.exists())
{
QDir dir = tmpinfo.dir();
dir.remove(newpath);
}
QFileInfo newinfo(path);
QDir newdir = newinfo.dir();
newdir.rename(path,newpath);
}

QFile file(path);

if(!file.open(IO_WriteOnly | IO_Append))
{
return;
}
QTextStream ts(&file);

ts << (*str)+"\n";
file.close();
delete str;
}

return;
}





taskmanager.cpp

#include "taskmanager.h"


TaskList tasklist;

void taskmanager :: stopAllTasks()
{
Task *t = tasklist.first();
while(t) {
t->stopnow();
tasklist.remove(t);
t = tasklist.first();
}
tasklist.clear();

}

void taskmanager :: addTask(Task *t)
{

// Task *t = tasklist.getlast();

//add task to the list
tasklist.append( t );

}

int taskmanager :: getCountTasks()
{
return tasklist.count();
}

summer_of_69
15th May 2009, 09:03
Sorry forgot to mention I am invoking this thread in MainWindow constructor.


############Mainwindow.cpp#############
MainWindow::AppMainWindow(QWidget *parent, Qt::WFlags flags)
: QMainWindow(parent, flags)
{
LogTask *log = new LogTask();
log->start();

Log(QString("Start Creating Actions\n"));

createActions();

Log(QString("Start Creating ToolBar\n"));
createToolBar();

Log(QString("Start Creating Menus\n"));
createMenus();
}


Thanks in Advance.
----

wysota
15th May 2009, 09:31
You are calling a method on the thread object from the main thread thus it is executed in the context of the main thread and not your logging thread.

summer_of_69
15th May 2009, 09:45
"You are calling a method on the thread object from the main thread"

I didn't get this.:confused:

talk2amulya
15th May 2009, 10:29
try changing your thread's affinity by using moveToThread like this:


myOtherThread->moveToThread(myOtherThread);

summer_of_69
15th May 2009, 10:56
I don't know but this is very strange problem I am facing.

It's working perfectily OK with only one Log(QString("")) , problem occurs when I introduces some more Log(QString("")) in different functions. :(

E.g.
If I comment
Log(QString("Start Creating ToolBar\n"));
Log(QString("Start Creating Menus\n"));

Than application will work fine and Log file is also created .

Is everything OK with QString.???

I am unable to track the error.:crying:

summer_of_69
15th May 2009, 10:59
I don't know but this is very strange problem I am facing.

It's working perfectily OK with only one Log(QString("")) , problem occurs when I introduces some more Log(QString("")) in different functions. :(

E.g. (
If I comment these two lines
Log(QString("Start Creating ToolBar\n"));
Log(QString("Start Creating Menus\n"));

and leave
Log(QString("Start Creating Actions\n"));

Than application will work fine and Log file is also created .)

Is everything OK with QString.???

I am unable to track the error.:crying:

wysota
15th May 2009, 11:03
"You are calling a method on the thread object from the main thread"

I didn't get this.:confused:

The context of execution is based not on the thread affinity of the object (which is also living in the main thread so this doesn't change anything but for a moment let's assume it does) containing the called method but on the affinity of the object calling the method. So if you are calling the method from your main window, it will be executed in the context of the thread running your main window (which is the main thread) and your gui will get blocked.

I don't know what your acceptEvent() method does but unless it calls QCoreApplication::postEvent() you're using a synchronous call which is again done in the context of the calling thread and blocks your gui because it is your gui thread that makes the call.


try changing your thread's affinity by using moveToThread like this:


myOtherThread->moveToThread(myOtherThread);

This will change exactly nothing, unless of course postEvent() is used by acceptEvent().

summer_of_69
15th May 2009, 11:25
I don't know but this is very strange problem I am facing.

It's working perfectily OK with only one Log(QString("")) , problem occurs when I introduces some more Log(QString("")) in different functions. :(

E.g. (
If I comment these two lines
Log(QString("Start Creating ToolBar\n"));
Log(QString("Start Creating Menus\n"));

and leave
Log(QString("Start Creating Actions\n"));

Than application will work fine and Log file is also created .)

Is everything OK with QString.???

I am unable to track the error.:crying:
But I can't understand why it's working for above condition ,I send just before your mail.

summer_of_69
15th May 2009, 11:26
But I can't understand why it's working for above condition ,I send just before your mail.

summer_of_69
18th May 2009, 07:56
The context of execution is based not on the thread affinity of the object (which is also living in the main thread so this doesn't change anything but for a moment let's assume it does) containing the called method but on the affinity of the object calling the method. So if you are calling the method from your main window, it will be executed in the context of the thread running your main window (which is the main thread) and your gui will get blocked.

I don't know what your acceptEvent() method does but unless it calls QCoreApplication::postEvent() you're using a synchronous call which is again done in the context of the calling thread and blocks your gui because it is your gui thread that makes the call.



This will change exactly nothing, unless of course postEvent() is used by acceptEvent().

Thanks for your reply .:)
This is what my acceptEvent() does.Still I am facing the same problem don't know from where to call my LogTask .




Task::Task():QThread() //constructor for task
{
taskmanager::addTask(this); //adding task to the tasklist
stopsignal = false;

}

void Task::run(){
while (!stopsignal)
{
mymutex.lock();
mycondition.wait(&mymutex);

// got a signal..now process
processIncomingEvents();
mymutex.unlock();

}
}

void Task::processIncomingEvents()
{
QEvent* e = mypocket.first();
while (e){
handleEvent(e);
mymutex.lock();
mypocket.remove(e);
mymutex.unlock();
e = mypocket.first();
}
//mypocket.clear();
}

void Task::acceptEvent(QEvent* ev){
mymutex.lock();
mypocket.append(ev);
mymutex.unlock();
mycondition.wakeAll();
}
;

wysota
18th May 2009, 09:43
I'm not sure why you are making things so complex, try this:

class LogEvent : public QEvent {
public:
LogEvent(const QString &str) : QEvent(QEvent::MaxUser-1), m_str(str){}
const QString &string() const { return m_str; }
private:
QString m_str;
};

class Log : public QThread {
public:
Log(){}
void run(){ exec(); }
static void log(const QString &str){ QCoreApplication::postEvent(new LogEvent(str)); }
protected:
void customEvent(QEvent *e){
if(e->type()==QEvent::MaxUser-1){
logData(static_cast<LogEvent*>(e)->string());
}
}
};

No need for any mutexes or artificial event queues.