PDA

View Full Version : Multithreading on window constructors



nagendrababu
2nd July 2018, 23:38
Hi All,
I am developing an Widgetapp, Which has MainMenuWindow(480*800 pix) with QStackedwidget(480*500 pix) in it. I have added all my other windows(around 10 each with multiple widget's inside them) to stacked widget. The reason for this approach being, The top and bottom menu options are common across all windows, which I added to MainMenuWindow, based on Menu selected I am changing stacked widget index to show the corresponding window.
But the problem with this approach is, On bootup of the system, I am calling MainMenuWindow constructor which calls all other window constructors inside it. But all this process taking up around 1-2 Minutes, Which is causing my app fall outside acceptable bootup delay range of 15-30 secs.
I am thinking of initializing threads for each window constructor to run them in parallel, and wait for all threads to finish after constructor is done. But not sure how feasible this solution would be.
Any help in this prospect of how to do this in a graceful way or any better idea to solve this unwanted delay?

Thanks,
Nagendra.

Lesiok
3rd July 2018, 11:01
You have to tell what takes so much time. Only then can you wonder how to solve the problem.

nagendrababu
3rd July 2018, 18:56
Hi @Lesiok,
it's window constructors taking that much time. As I mentioned previously,I added all my windows to stacked widget of MainMenuWindow(My main window). So When I Invoke MainMenuWindow constructor, constructors of all other windows which to be added to stacked widget are also called there, and added to stacked widget So all the time is to finish the MainMenuWindow constructor alone.

-Nagendra

d_stranz
3rd July 2018, 22:56
Widget constructors take almost no time to execute. I have apps with many tens of widgets that start up almost instantly. You are probably doing something wrong. But since you haven't shown any code at all, it's impossible to tell you what that might be.

nagendrababu
5th July 2018, 00:35
Hi @d_stranz,
I was also in impression that constructors don't take much time, But In my current application I am seeing it. So to give you clear Idea I have profiled time taken by each window constructor alone.

// Time taken by each screen constructor in ms
Elapsed time Screen1 1609
Elapsed time Screen2 0
Elapsed time Screen3 343
Elapsed time Screen4 2178
Elapsed time Screen5 44
Elapsed time Screen6 2916
Elapsed time Screen7 179
Elapsed time Screen8 563
Elapsed time Screen9 26077
Elapsed time Screen10 1790
TOTAL: 35699ms

// Time to add all these objects to mainMenuWindow stacked widget
Total Stacked widgets: 10
Elapsed time to stack all widgets 15761


My MainMenuWindow constructor is as follows:


LoginScreen = new LoginWindow(this);
welcomewindow = new Welcomewindow(this);
AutoControlScreen = new AutoControl(this);
AdjScreen = new Adjustment(this);
HeatScreen = new Heat(this);
InfoScreen = new Information(this);
IntensityScreen = new Intensity(this);
ManualScreen = new Manualcontrol(this);
SettingsScreen = new Settings(this);
UsersScreen = new UsersMemory(this);

#ifdef DEBUG
if(welcomewindow == NULL)
qDebug() << "Dummy Welcome window Object is Null \n";
if(LoginScreen == NULL)
qDebug() << "Login screen object is Null \n";
if(AutoControlScreen == NULL)
qDebug() << "AutoControl screen object is Null \n";
if(AdjScreen == NULL)
qDebug() << "Adj screen object is Null \n";
if(HeatScreen == NULL)
qDebug() << "HeatScreen object is Null \n";
if(InfoScreen == NULL)
qDebug() << "InfoScreen object is Null \n";
if(IntensityScreen == NULL)
qDebug() << "IntensityScreen object is Null \n";
if(ManualScreen == NULL)
qDebug() << "ManualScreen object is Null \n";
if(SettingsScreen == NULL)
qDebug() << "SettingsScreen object is Null \n";
if(UsersScreen == NULL)
qDebug() << "UsersScreen object is Null \n";
#endif
if(welcomewindow == NULL || LoginScreen == NULL || AutoControlScreen == NULL || AdjScreen == NULL || \
HeatScreen == NULL || InfoScreen == NULL || IntensityScreen == NULL || ManualScreen == NULL || \
SettingsScreen == NULL || UsersScreen == NULL)
{
qDebug() << "Windows creation Failed, Exiting the Application\n";
exit(1);
}
//************************************************** *****************
// Setting All Mainscreen as stackable objects to MainMenu Screens
//************************************************** *****************

ui->stackedWidget->insertWidget(S_Welcome,welcomewindow);
ui->stackedWidget->insertWidget(S_Auto,AutoControlScreen);
ui->stackedWidget->insertWidget(S_Manual,ManualScreen);
ui->stackedWidget->insertWidget(S_Settings,SettingsScreen);
ui->stackedWidget->insertWidget(S_Info,InfoScreen);
ui->stackedWidget->insertWidget(S_Heat,HeatScreen);
ui->stackedWidget->insertWidget(S_Adj,AdjScreen);
ui->stackedWidget->insertWidget(S_Intensity,IntensityScreen);
ui->stackedWidget->insertWidget(S_Users,UsersScreen);
qDebug() << "Total Stacked widgets: " << ui->stackedWidget->count();



Please Suggest how can I improve the timeline.

Lesiok
5th July 2018, 07:05
Show Settings() constructor - if this is screen9.

nagendrababu
5th July 2018, 08:38
Hi @Lesiok,
this is my settings page constructor. This screen is having around a total of 100 widgets arranged as pages.



Settings::Settings(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::Settings)
{
this->setWindowFlags(Qt::Window | Qt::FramelessWindowHint);
PasswordScreenPage = new PasswordScreen(this);
ui->setupUi(this);
this->setCursor(Qt::BlankCursor);
ui->stackedWidget->insertWidget(PasswordChangePage,PasswordScreenPage );
}


Thanks,
Nagendra.

Lesiok
5th July 2018, 09:29
Are You running debug or release code ? The debug code contains many asserts, which makes it slow, especially container operations.

d_stranz
5th July 2018, 20:37
Settings::Settings(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::Settings)


Why are you calling the QMainWindow constructor from the Settings constructor? Does this widget really inherit from QMainWindow? And if so, why are you adding something based on QMainWindow into a stacked widget which is itself inside a QMainWindow?

nagendrababu
6th July 2018, 08:17
Hi @d_stranz,
Yes all these are inherited from QMainWindow. The evolution of this application is, Initially started with creating individual screens of full screen dimension(800*480) But when changing between screens there is visible transition which looks like application running very slow. So then We have changed all windows to dimension of stacked widget(500*480) and added them to stacked widget of MainMenuWindow. From the qt forum posts I read, I understand this can be done so we went ahead with that approach instead of rewriting entire application.

Do you think this approach is causing this much delay? If that's the case from which template these screens should be inherited. QDialog or QWidget?

Thanks,
Nagendra.

d_stranz
6th July 2018, 22:39
That must be a very confusing GUI for users. You have the outer QMainWindow (that contains the stacked widget) and it has a menu. toolbar, and status bar, then inside that you have -more- QMainWindow classes, and each of them has a menu bar, toolbar, and status bar. Is that really what it looks like?

A typical application has a window hierarchy like this:


QApplication
QMainWindow
QWidget (central widget) - in your case this is QStackedWidget
QWidget(s) - one for each page in the stack, including layouts

Your application must look like this:


QApplication
QMainWindow
QStackedWidget (as central widget)
QMainWindow 1
and what as the central widget?
QMainWindow 2
and a different central widget?
...

Sounds very strange to me. I would replace all of the QMainWindow instance you use in the stacked widget with plain QWidget.

nagendrababu
7th July 2018, 01:22
Hi d_stranz,
I agree It might not be a good way, But as I told previously The evolution of app made us to take this kind of decision. And coming to UI, it don't has menubar, toolbar or status bar, So it looks cleaner and easy.


QMainWindow
QStackedWidget
QMainWindow:1
centralwidget
all widgets under this screen
QMainWindow:2
centralwidget
all widgets under this screen


I agree with the change, that All these windows should be Qwidgets, But it's like rewriting all my application again.
So do you think the constructors delay is caused by my approach only?

Thanks,
Nagendra

d_stranz
8th July 2018, 04:56
So do you think the constructors delay is caused by my approach only?

I can't see any other reason for it, but then you haven't showed much code. If your sub-main windows don't have menus or toolbars, then it makes no sense at all to do it the way you are doing it. It's a lot of overhead for absolutely nothing. You could just simply add your central widgets to the stacked widget and achieve the same thing.

nagendrababu
8th July 2018, 07:08
Hi @d_stranz,
I tried creating one of the window as Qwidget type instead of QMainWindow type and calculated time to execute the constructor in each case.
In case of QMainWinow:
Elapsed time Screen1: 1600ms
In case of QWidget:
Elapsed time Screen1: 1589ms

So from these metrics, I don't see much difference in time taken by constructor.

To be additional Question,
Is there any way we can implement threads to divide constructors between them to run them in parallel.

I tried something like this:


// Thread1 to init screens except Settings
Thread1 = new QThread;
connect(Thread1, SIGNAL(started()), this, SLOT(thread1_run()),Qt::DirectConnection);
connect(this, SIGNAL(thread1Finished()), this, SLOT(thread1_finish()));
// Thread2 to init Settings screen(Heavy Screen)
Thread2 = new QThread;
connect(Thread2, SIGNAL(started()), this, SLOT(thread2_run()),Qt::DirectConnection);
connect(this, SIGNAL(thread2Finished()), this, SLOT(thread2_finish()));
// Stack widgets
connect(this,SIGNAL(threadsDone()),this,SLOT(stack Widgets()));
Thread1->start(QThread::HighestPriority);
Thread2->start(QThread::HighestPriority);

But from Above code, The threads are executing one after another. They aren't running parallel. Can you help how to run these parallel?

Thanks,
Nagendra

d_stranz
8th July 2018, 21:08
Can you help how to run these parallel?

Not possible in Qt. GUI objects (things inheriting from QWidget or QWindow) can be created only in the thread that owns QApplication, and you can have only a single QApplication instance.

You need to do an experiment, I think. Create a new QMainWindow-based application, put a QStackedWidget as the central widget for the main window, and then just add a bunch of QWidget-based pages to them. Don't use your existing classes. Use QTreeView, QTableView, QGraphicsView, whatever. Time how long that takes. I think you'll find that your bottleneck is not in building your GUI, it's whatever you are doing in your application's sub-window constructors that's the cause.