QThreadPool with multiple threads?
I'm a noob. I admit it.
I'm working on a little app that needs to execute a set of tasks, each at a given time. I think I'd like to put each task into it's own thread with a QTimer and do the work on a timeout event.
I'm struggling with understanding the best way to do this... QThreads in an array and a thread manager? QThreadPool? QtConcurrent::run?
I've reviewed a lot of documentation and examples, but the examples are all pretty simple and only show cases where a single task is pushed into a thread. I can't find any that show me how to have, say, 10 threads, how to keep track of which ones are finished, which one are still active, etc.
does anyone have any leads or links? i'm happy to go read and experiment, i'm just not sure on what I'm looking for.
Qt Qt Evellyn
... helped me a lot.
and this one:
is a very nice example too.
First of all, are you familiar with the concept of event-driven programming, and/or "signals and slots":http://qt-project.org/doc/qt-5.1/qtcore/signalsandslots.html ? These are powerful mechanisms in Qt. With them, you can (should) think about threads in a different way compared to traditional multithreading tools (say, pthread).
[quote]I’m struggling with understanding the best way to do this[/quote]You'll have to describe your tasks in more detail.
How far apart are the trigger times? How long are your tasks? Does each task run just once, or repeatedly?
[quote]I’m working on a little app that needs to execute a set of tasks, each at a given time.[/quote]If your timer intervals are longer than the time it takes to run each task, you might not need multiple threads at all.
Just attach each task to a different call to QTimer::singleShot(). The tasks will start running when the timer times out.
[quote]I can’t find any that show me how to have, say, 10 threads, how to keep track of which ones are finished, which one are still active, etc.[/quote]Is there a reason you need to query the status of each task regularly? If not, you could just let the task emit a signal when it's done. Then, a slot can respond to the finished task.
Thanks for the videos Qt Qt Evellyn! those did help solidify some concepts.
JKSH, here's some answers.
I'm reasonably familiar with event driven programming. still getting used to some of the unique features of QT signals and slots, but I am comfortable with the concepts, and I am considering them as I ponder this problem.
you could think of my app as a cron daemon of sorts. the user can specify a task, the time at which it should run, and whether it should repeat at some interval. there would be anywhere from 0 to many tasks, but i'd imagine practically there would probably be 5-10-ish tasks scheduled at any given time. I am considering having one thread act as the "controller", and have it loop through a list of tasks to schedule, and using a singleShot to run them once, then having the controller schedule the next run on a loop. i.e.:
in the controller:
@for task in tasklist,
if task needs to be scheduled, schedule it to run once with singleShot
my original idea was to spin off each task in a thread and use a timer to execute the task on a timeout event. i.e.
for each task in tasklist;
create an instance of a Worker class
set the interval for the Worker to be equal to the frequency the task needs to run at
move the Worker to a thread
repeat for the next task
I don't necessarily need to query the status of each task. However, I would like to know when things happen within a task so i can take some actions in the GUI. I could use signals and slots for that, I understand.
There's also case where a task needs to be modified. So for example, a user might change the interval that a task executes on, or they might need to modify some other properties of the task, like an input parameter for example. the user does this using the GUI, but then i'd need to cancel the current task/thread, update the object with new properties, then start it again. I suppose i could do these with signals and slots as well, but I still have the problem of having a bunch of tasks, each one running in it's own thread, and how to manage those... how to add new ones, or delete existing ones if the user no longer wants them to execute, etc..
that's a long reply. hope that provides some context.
any further thoughts would be greatly appreciated!
Thanks for the detailed reply; it does help others understand your issue better.
I asked a really similar question myself last year. See Tobias' answer: http://qt-project.org/forums/viewthread/19681/ Using a QTimer to initiate a task directly can make the task run at the wrong time if the clock is changed.
So, instead of having many timers running at the same time, just have one timer (in the main thread) fire every minute. In the associated slot:
for each task in tasklist
compare scheduled time to current time
if time is up
This way, it's trivial to update/add/remove tasks -- just update the task list, and the scheduler will see the changes the next time it wakes up.
Again, if your tasks are short, you don't need threads at all. If they are long, have a look at the "thread comparison page":http://doc-snapshot.qt-project.org/qt5-stable/threads-technologies.html to get started.
- If your tasks are very short, just run them in the main thread.
- If your tasks are medium-length, you can't run them in the main thread, or else they will cause your GUI to freeze. You can run them using QRunnable or QtConcurrent::run()
- If your tasks are very long, you can't run then with QRunnable or QtConcurrent::run(), because those use a thread pool that only allow a limited number of tasks to run in parallel at a time; if all threads in the pool are busy, a new task will have to wait until one of the old ones finish. You will need to spawn a new thread using QThread.
[quote]I don’t necessarily need to query the status of each task. However, I would like to know when things happen within a task so i can take some actions in the GUI. I could use signals and slots for that, I understand.[/quote]Yes, updating the GUI is best done by sending a signal to it whenever you want to update.