Solved QFile, QThread, QConcurrent and how to Qt
-
@A-Newbie said in QFile, QThread, QConcurrent and how to Qt:
I do understand I am using different technologies, but as I am still learning I want to test how they all work - together or separately, hence the reason I asked if in the long run would be better to manually create threads and move workers on them manually so I can be able to manage them, instead of using QtConcurrent.
Here is the answer you won't like: it all depends on the thing you want to do.
In any case, you would usually not invoke QtConcurrent code from a separate thread since QtConcurrent provides a high level set of functions that does the threading for you. To illustrate the issue, you are calling run and right after that you call waitForFinished on the future watcher. This defeats the purpose of using QtConcurrent since you are blocking the execution until run has ended.
You should by learning the way Qt implement its asynchronous paradigm using signals and slots. This will allow you to have a better grasp on how to use QtConcurrent properly.
You can then play with QThread, separately from QtConcurrent. You'll see that you do not need to use them both at the same time the way you did.
-
Hi, and thanks again.
I don't mind the answer at all. On the contrary I am aware that everything depends on what you really want to do so apologies if my explanations or questions are/were vague/incorrect. This is the reason why I tried to explain in more details the purpose of the code I posted and how I would want to possibly evolve it but I guess I didn't do a very good job :<
I know the thread is blocked, as explained in the initial post and I want my thread to be blocked(or I think I do) until it is finished as I want the worker as an object to self-destroy once it's done doing it's job, or to be able to interrupt the worker's job at any point if need be. If I only do the QtConcurrent run on the write function it will execute in a separate thread(than the worker's thread) and I(personally) don't know how to control that thread if it has to be interrupted or something of the sort. This is the reason why I asked if there is a way to control the QtConcurrent thread(s), or in the long run if I want control my threads to use QThread and move the worker to the newly created thread, thus be able to stop the worker/thread at any time using QThread's signals/slots.
If there is a more elegant way to handle this scenario by all means please do tell.I just want to know how much I can do with either. For example, I would go any day with QtConcurrent if I simply want to create 1000 files and fill them up with raw data, but then again I am not sure how achieve the same concurrency/async logic if I simply want to fill or read from/to a single file. I mean yes, I can fire the same read/write function in QtConcurrent but I can hardly imagine the OS letting me write chunks of data from multiple threads as they will eventually overlap and cause file corruption(with a normal file), which means if the OS wouldn't let me do that the only other thing that makes sense to me is QDataStream instead of QFile for the task, but since this is simply a speculation on my behalf I really wanted someone to shed more light in this regard.
I am still interested in those two as well:
I have finally made the QTimer works as I want it(I think) but I am not sure if it's the correct way of doing things. To get it going I had to:
QThread* timerThread = new QThread(this); QTimer * timer = new QTimer(0);
but I can't wrap my head around just yet as to why I had to do that since by my manager class and QThread are inheriting QObject. The same applies for QTimer. Why do I have to give my class object as parent for the new thread and null the timer?
Furthermore, for signal/slot connections made in my manager class constructor(not sure if it's the best idea) in this particular case I had to do:
QObject::connect(timerThread, SIGNAL(started()), timer, SLOT(start()),Qt::QueuedConnection); QObject::connect(timerThread, SIGNAL(finished()), timer, SLOT(stop()),Qt::QueuedConnection);
which took some time to figure out(not the problem here) but then again I am not sure why the usual approach like the one below is not working:
connect(newManager,&manager::start, newWorker, &worker::start, Qt::QueuedConnection);
connect(newManager,&manager::stop, newWorker, &worker::stop, Qt::QueuedConnection);
Could you please elaborate on that?I do understand these things might be trivial for most people here but wrapping my head around these for me is like jumping few levels at once so the extra nudge here would be highly appreciated.
-
@A-Newbie said in QFile, QThread, QConcurrent and how to Qt:
I mean yes, I can fire the same read/write function in QtConcurrent but I can hardly imagine the OS letting me write chunks of data from multiple threads
Why do you want to write to same file from different threads? Only one thread should do the writing. Other threads can communicate with that thread via signals/slots to provide the data to write.
"Why do I have to give my class object as parent for the new thread and null the timer?" - you don't have to, you can. Check https://doc.qt.io/qt-5/objecttrees.html Short explanation: if parent ("this" in QThread(this)) is deleted it deletes its children (QThread instance in this case). If you do the memory management by yourself you do not have to pass parent.
"null the timer?" - why do you think you have to pass null? You can, but then you have to delete it manually later. Or you pass "this", then the timer will be deleted as soon as "this" is deleted.
-
@A-Newbie
If I may suggest a git repo of mine:
https://github.com/DeiVadder/QtThreadExampleIn that project I do a threading task in each of the "Qt"-ways
The related functions are numbered.May help you further in your quest for knowledge 😉
-
Hello again,
@jsulm
I am not sure if I want to use many threads(among other things) to write to the same file, which is the reason I am asking how performance tools achieve this exactly. Many data IO performance bench tools have an option called "overlapped IO and IO depth", "concurrent IO count", "Outstanding IO" or something of the sort. In either case increasing the IO numbers to something adequate, say 3 or 4 brings about better read/write performance results from a single file, while a single-threaded sequential IO cannot do that.
I can probably simulate the same performance results if I shoot multiple threads reading from or writing to multiple files, but I am struggling at this point to understand how to do it with a single file.As for the new thread and timer, while I am aware of the parent-child relationship, but for some reason this timer wasn't working before I did that. Might have been just a coincidence in case I had my Qt::Connection was set to Queued instead of Direct at the time, or messing something some signals/slots up, or something of the sort, but I did spend the whole night reading forums as my timer wasn't working if moved to a different thread.
The reason I didn't pass my class as a parent to my timer is because of the Thread Affinity explained here: https://doc.qt.io/qt-5/qobject.html assuming I got the explanation there right of course =)
I can swear I didn't touch my signals/slots and tried Queued vs Direct connection every time I was changing something else.
In either case by all means it seems I goofed up something so I will settle with that, as it explains why I couldn't explain what happened there ^_^@J-Hilk
Thanks a bunch, having some good examples really means a lot to me! It gave me some good insight, but I mean to ask about the subclassing from QThread method. I read a lot of posts implying this is not the best method to handle threads. Is this because you have to be more wary of where and how you create things when you inherit from QThread in general and people struggle with this part, or is it something else?Also there is something which @SGaist said and has been bugging me:
"In any case, you would usually not invoke QtConcurrent code from a separate thread since QtConcurrent provides a high level set of functions that does the threading for you."
Besides the obvious reason, namely taking one additional thread(more resources) for the task what are the downfalls here? Is it something in general or more of a Qt thread methods/technology related?Any clues about why I had to use two different signal/slot connection methods?
-
@A-Newbie said in QFile, QThread, QConcurrent and how to Qt:
Any clues about why I had to use two different signal/slot connection methods?
What exactly did not work with the other approach?
-
@A-Newbie said in QFile, QThread, QConcurrent and how to Qt:
mean to ask about the subclassing from QThread method. I read a lot of posts implying this is not the best method to handle threads. Is this because you have to be more wary of where and how you create things when you inherit from QThread in general and people struggle with this part, or is it something else?
Well in general it is very easy to make something wrong. You have to have an fundamental understanding of Qt Object, &- Parent/Child system Threadaffinity in combination to the caller etc.
If you do an endless loop you'll have to implement your own check & abort functionality and if you call exec() you might as well do the Worker approach.
Besides the obvious reason, ..., what are the downfalls here
QtConcurrent provides, amongst other things, an integrated ThreadPool management, which is nice, but the whole thing comes with an overhead, so much in fact, that QtConcurrent is its own module, whereas QThread is part of QtCore
Any clues about why I had to use two different signal/slot connection methods?
care to elaborate?
-
-
@A-Newbie start is overloaded, it excepts an int and a void parameter
The docs actually have an example for exactly this one,
https://doc.qt.io/qt-5/qtimer.html#detailson how to correctly call the overload in connect
QTimer *timer = new QTimer(this); connect(timer, &QTimer::timeout, this, QOverload<>::of(&AnalogClock::update)); timer->start(1000);
-
@J-Hilk
Thanks again, I got it going with QOverload<>::of , but I am confused. Since I am passing it a void signal shouldn't it automatically choose the void version of the slot as normal overloads do?
Do the macro version, which I actually used do some sort of additional checks and adjustments and it works fine, or was it just luck it worked out for me and it chose the correct slot version? -
@A-Newbie
Hi
The difference between new syntax (the one needed overload )
and SIGNAL/SLOT macros is how that the new syntax works compile-time and the old
macro-based , works runtime.
The new syntax is based on pointers and needs full type info, the
old Macro version looks up the names at runtime.more info:
https://wiki.qt.io/New_Signal_Slot_SyntaxYou can see why the new syntax needs the QOverload in cases where there is
signals with the same name but different parameters. like int and string. -
@mrjj
Hi and thanks, this was an eye opener as I had no idea about the whole overloading thing. Never met it in any of the learning materials I went through so far.Regardless, I got answers pretty much to all of my questions and everyone helped a lot. Is there a way to simply have this topic as solved without picking a specific answer?
-
@A-Newbie said in QFile, QThread, QConcurrent and how to Qt:
Regardless, I got answers pretty much to all of my questions and everyone helped a lot.
great 👍
Is there a way to simply have this topic as solved without picking a specific answer?
sure bottem right side, topic tools button, simply set it to solved there