 Next let's look at something that's called an object pool. Now I don't mean a swimming pool. What we're going to do is we're going to create a limited amount of workers that can do a larger pool of work and that's why it's called an object pool. So we're going to have a worker and we're going to have a pool. The first thing you need to understand is that the worker really doesn't need to know anything about the pool. It just needs to know what work it needs to be done. So we're going to say worker. This is a Q object, of course. And let's add a new class and call this pool. What the pool does is it actually holds the work that needs to be done and then determines if workers are ready for that work. Once a worker is ready, it hands the work off and just trusts that the worker is going to do its thing. Let's go ahead and flesh out our worker here. We're going to say Q timer and let's do a Q random number generator. And of course, let's conclude Q debug. For our public, we're going to say bool is busy. Signals. We want a couple of signals here because we're going to be communicating outside of this class. So we're going to say void started. We want to know when the actual work was started, finished. And then for our slots because we want to actually get some information here. We're going to say void time out. That really could be a private one. So here's our actual work function right there. That's where the work's going to happen. And then let's have a local Q timer. Let's call this M timer. And a boolean value called M busy. Let's go ahead and flesh this out. All right, like I said, the workers only job in life is to perform work. It doesn't care what other workers are doing. It doesn't care what the pool is doing. It just wants to do its job. Gosh, that would be nice if you could just do your job. I have those days at work where you're just like, I could just do my job. That'd be great. All right, so on the timeout we're going to say M busy equal false and we're going to emit our finished. You guessed it, we're just using the timer to fake like we're actually doing something. So we're going to actually be that coworker that just kind of sits at their desk and looks busy, but we're not actually doing anything. So we're going to say Q info starting work and we want to just say this is what we're going to be working on. And we're going to make a Q random number generator. We want a random number from our singleton pattern. There we go. And we want this bounded now that you understand what a singleton pattern is between 1000 and 5000 and busy is now suddenly true. We really should have put this up here. And then we're going to say m timer dot single shot meaning we're just going to do this one time and emit that we're actually starting. So really if you follow along, all we're doing here is we're saying we have a function that returns is busy. Just going to return that value and we have a timeout which is just going to say, hey, we're no longer busy and admit that we're finished. So the pool can determine, hey, this worker is suddenly not doing anything productive. Let's put them to work. When this worker is asked to do work though, we're just going to basically just grab a random number between 1000 and 5000 and we're going to do a timer single shot, which is going to be the, well, you guessed it, the number. So any random number between one and five seconds basically when it's done, it's just going to call this timeout basically saying we're free. Last, it's going to emit the started signal that way. The pool knows that, hey, this worker is now busy. Don't bother him. Let's go to our pool and let's include a few things here. Let's include queue to bug. Let's include queue vector and queue timer and worker. Here we go. So the pool's job is a little bit different. The pool needs to know a what the work is and b what the workers are doing. So we're going to have a deconstructor in here because we're going to have some resources that we need to keep track of and we want some public slots and let's do check work. Now we're going to have a queue vector. This is going to be a list of workers, actually say pointers to workers. We're going to have another queue vector. This one's going to hold the actual work and we're going to have a timer. All right, seems like it's going to be a pretty complex class and we do have a little bit of typing in front of us, but I think we can get through it. Let's take a look at our constructor here. We're going to say four into i equals zero i is less than, uh, let's say five. So we're just going to have five workers basically. So we're just going to create our pool here. We're going to say worker. Let's just call that w. We're going to use queues built-in automatic memory management because we don't have to mess with that. We're going to set the object name. We're going to set this to whatever number is the value of i and then we're going to connect our signals and slots. We're going to connect the started with this pools started. Now that we've got that, we can just simply copy this, paste it and change this to finished, change that to finished. Now let's go ahead and append this to our list of workers. Right off the bat, you should be noticing a problem. We have these pointers which are going into this worker. I should say that going into this list of workers. So we have a pointer going in here. Now we're using queues built-in memory management, but it makes me wonder if it's actually going to work as expected. So just in case queued delete all won't do a darn, won't do a darn thing. Some may argue it's really not needed. And while we're in the deconstructor, let's just do m timer dot stop just to make sure that timer is actually shutting down the way it's supposed to. And let's put some sort of notification on the screen that the worker is ready for work. There we go. We're going to grab this. And let's connect up that timer. Say queue timer, timeout with this timeout. We actually didn't want timeout. We want to check work. That's why that was there. So that should give you a little idea of what's going on here. We're going to have work, which is going to actually add work into the pool, start and finish these or slots that are going to be called by our workers, and then check work. This is going to be the timer periodically going out here and checking for extra work. Let's say m timer. We're going to set the interval and let's set this for 200. That's right, 200 milliseconds. So this is going to go a few times a second. I'm going to say m timer start. So we're going to just start looking for work right away. When we start looking for work here, actually let's add that. I should say when somebody tries to add work, we're going to say m work dot append. And we're just going to append that value. And then immediately check to see if we have a free worker. That's right. We're going to just manually call this started. Here we're going to say worker. And we want a queue object cast a pointer to the worker using the sender. If you remember from our previous conversations, the sender is the object that emitted the signal. We are in the slot, but we want to know who actually emitted it. So let's go ahead and say queue info, get the object name out of that object. And we just want to know finish. So we're going to do the same thing here. Check work is, well, where we check our work. This is going to be time called by us whenever work is added. And also when the timer times out. So if we have no work, then we're just simply going to return. Meaning it's just pointless for us to stay here because we have really nothing to do. For each worker in our workers vector, we're just going to say, all right, if the worker is busy, actually, if it's not busy, meaning it's just sitting there doing nothing, you know, Bob sitting there reading the comics, then we're going to say, Bob get to work, and we're going to give it the actual work. And we're going to take the first one. Now what take first does is actually pulls the value out of the vector and returns it immediately. Saves us a little bit of extra typing. And if we have just cleared that list, then we're just simply going to return out of there. So looking at this, it's pretty simple, pretty self explanatory. But just to cover, we're going to create five workers. We're connecting up the signals and slots. Then we're going to start a timer. That timer is going to have an interval of 200 milliseconds. When we delete this pool object, we're going to stop the timer, flush out any pointers, clear the list. Don't really need to do that, but we're going to do it anyways. And then as we add work, we're going to append it to our list of work and immediately check to see if we have any free workers. If we don't, it's just going to skip right over this. And every time that fire that every time that timer fires off, then it will check this again. All right, so what's the point of all this? We've done a lot of typing and a lot of moving around, but what are we really doing? Well, we're saving resources here. Let's say each one of these workers is really, really super resource intensive. Well, we may not have the computing power to do it all at once. So we're going to say pool P for int i equals zero i plus plus. Oops, actually i is less than 100. Let's just make 100 of these i plus plus. There we go. And that's why we added the timer in the worker. So just to kind of simulate some sort of long running thing. So we're just going to add some work, save this, and let's run it. And you can see how it is just going and going and going. And this will run and run and run until all the work is done. Now think of this in terms of, for example, something that's really limited, like sockets or a good example or threads. Threads are very expensive. Sockets, there's a limited number. So you'd want a socket pool. You'd say, hey, only use 20 sockets. And if the socket's busy, reject the connections. Threads is a better example because there is something called a Q thread pool, which really says, hey, threads are expensive, but threads back to our doing the dishes analogy. Instead of doing dishes one at a time, you would do all the dishes at once and save yourself 20 minutes of scraping plates. The problem is threads are very memory costly, and I should say very resource intensive on the computer. Not really these days, but back when they were first created, they were very expensive. Now you can have threads everywhere. I almost guarantee you every process has at least four or five threads running. All right, so now we see all the work was completed and finished. Those workers are just sitting there now idle waiting for more work. And if we added more work in, you would actually see them start up similar to what was going on here. So you can see like started worker two, finished worker three, starting work 71, started worker three, that's right. Worker three finished, worker three said, hey, I'm free, put me to work. Worker zero finished, worker zero got put to work. So that is a good example of an object pool. When you have a lot of things you need to do, but you don't have a ton of resources, and you don't really care how long it takes, pools are a good way to go. I hope you enjoyed this video. It's part of a video series I have out on udemy.com. This particular video is a follow on in the intermediate course, but you can start in Qt Core for beginners. And if we just kind of crack this open, it's got a lot of content that'll take you from an absolute beginner that just knows absolutely nothing from Hello World all the way up to what are templates, generics, air handling and classes. This specific video is part of the Qt Core intermediate class. This picks right up where the beginners course left off and we do things like memory management, collections, working with settings, the file system, a lot of file system, compression, serialization and much, much more.